您现在的位置是:首页 > 编程 > 

(持续更新)逆向学习(KR 41笔记含随堂作业)

2025-07-21 19:13:12
C开始的学习之路 记不住的一些函数 #define _CRT_SECURE_O_WARIGS 关闭不安全函数的提示 #字符串和字符串函数 strncat(字符串,字符串,长度) strncat()拼接字符串的函数 strcmp(用户响应的, 已存储的) strcmp()把用户响应与已存储的字

C开始的学习之路

记不住的一些函数
#define _CRT_SECURE_O_WARIGS
关闭不安全函数的提示


#字符串和字符串函数
strncat(字符串,字符串,长度)
strncat()拼接字符串的函数						

strcmp(用户响应的, 已存储的)
strcmp()把用户响应与已存储的字符串作比较		
	char str1[] = 12;
	char str2[] = 124;
	int result = strcmp(str1, str2);
	if (result > 0)
	{
		printf(1>2);
	}
	else
	{
		printf(2>1);
	}


strcpy_s(需拷贝的数组,原拷贝的数组)
strcpy()拷贝整个字符串到目标数组里				

strncpy_s(数组,目标数组,长度)
strncpy()拷贝整个字符串到目标数组里更安全 		

sprintf(目标数组,打印内容,写入的条件1,条件2....)
sprintf()把数据写入字符串						

char* strchr(ct char*s,int c)
如果s字符串中包含c字符,该函数返回指向,s字符串首位置的指针,如果未到,则返回空指针

char* strpbrk(ct char*s1,ct char*s2)
如果s1字符中包含s1字符串中的任意字符,函数返回指向s1字符首位置的指针,如果未到,则返回空字符

toupper()
处理字符串中的每个字符,把整个字符串转换成大写

memset(数组名,要清理内存使用的数据,清理的字节数)
清空字符串 字符串初始化函数
char str1[10] = china;
memset(str1, 	a	, 10);

strlen()求字符串长度

fclose()关闭指定的文件,必要时刷新缓冲区
变量的作用域和生命周期

作用域:变量的作用范围(在何处能够访问到变量)

	全局变量:定义在所有函数之外的变量,定义之后都可以访问,而且数据共享(内存只有一块),从定义开始到程序执行结束
	局部变量:在函数或者代码块里面定义的变量,从定义开始到函数或者代码块结束
#define _CRT_SECURE_O_WARIGS

#include<stdio.h>

int num = 90;
void fun();
int main(void)
{
	num = 5;
	printf(%d\n, g_num);
	fun();
	return 0;
}

void fun()
{
	printf(%d\n, num);
}

根据变量的作用域和生命周期分类

全局变量和局部变量

静态变量和动态变量

栈区(stack)存放函数的参数,局部变量等,由编译器自动释放
堆区(heap)动态申请的内存存放在堆区,若不释放,
全局区(static)静态全局变量和静态变量存储是放一起的,里面细分有一个常量区,字符串常量和其他常量也存放在此,该区域在程序结束后又系统释放
代码区存放函数体的二进制代码

自动变量:没有任何存储类别修饰的变量,都是自动变量

静态变量:用static修饰的变量,就是静态变量,不会自动释放内存,而是程序结束之后系统自动回收,加了static生命周期延长了,作用域不变

register 表示吧变量放在寄存器(CPU)里面,注意:这个只是说给编译器建议,但是编译器不一定会采纳

extern 表示外部变量 这个一般用在多文件中 申明使用外部变量

int test_a = 50;

extern int test_a;
int main(void)
{
	printf(%d, test_a);

	return 0;
}
动态内存分配

动态内存是相对静态内存而言的,所谓动态和静态就是指内存的分配方式,动态内存是指在堆上分配的内存,而静态内存是指在栈上分配的内存

静态内存:比如局部变量、形参等

动态内存分配的意义

1、C语言中一切操作都是基于内存的

2、变量和数组都是内存的别名

、定义数组时必须指定数组的大小,使用动态分配可以在运行时调整大小

4、函数结束之后,不希望变量的内存被释放

malloc

#define _CRT_SECURE_O_WARIGS

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void)
{
	//栈区
	int num = 20;
	int* p = &num;

	//自动申请到堆区,成功返回申请到的首地址,失败返回null
	int* pn = (int*)malloc(sizeof(int)); //堆区地址

	//防御性编程
	if (pn == ULL)
	{
		printf(no\n);
		return -1;
	}

	*pn = 66;
	printf(%d, *pn);

	//释放,要设置他为ULL,以免后面不小心还调用
	pn = ULL;
	free(pn);
	return 0;
}
#define _CRT_SECURE_O_WARIGS

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void)
{
	int* parr = (int*)malloc(sizeof(int) * 5);

	if (!parr)//!parr==ULL
	{
		return -1;
	}

	//把parr这片内存全部初始化为0
	memset(parr, 0, sizeof(int) * 5);

	for (int i = 0; i < 5; i)
	{
		//printf(%d, *(parr  i));
		//printf(%d, *(parr)); error,错误,会越界
	}

	free(parr);
	parr = ULL;
	return 0;
}
结构体

结构体数组

#define _CRT_SECURE_O_WARIGS

#include <iostream>

struct stStudent
{
	int age;
	int level;
};
//代表有5个stStudent结构体的数组
struct stStudent arr[5] = { {0,0},{1,1},{2,2},{,},{4,4} };

void MyPrint()
{
	int a;
	int b;
	for (int i = 0; i < 5; i)
	{
		a = arr[i].age;
		b = arr[i].level;
		printf(%d %d\n, a, b);
	}
};

int main()
{
	MyPrint();
	return 0;
}
#define _CRT_SECURE_O_WARIGS

#include <iostream>

struct stStudent
{
	int Age;
	char name[0x20];
};

struct stStudent arr[];

void init()
{
	arr[0].Age = 20;
	printf(%s, strcpy(arr[0].name, china));
}
int main()
{
	init();
	return 0;
}
数组指针
int main(int argc, char* ar[])
{
	int arr[]={1,2,,4,5,6,7,8,9,10};
	int (*px)[2][2]=(int (*)[2][2])arr;
	printf(%d\n,(*px)[1][1]);//4
	px; //2*2*4,现在位置到5开始
	printf(%d\n,(*px)[1][1]);//8
	return 0;
}

调用约定
调用约定参数压栈顺序平衡堆栈
_cdecl从右至左入栈调用者清理栈
_stdcall从右至左入栈自身清理堆栈
_fastcallECX/EDX传送前两个剩下:从右至左入栈自身清理堆栈
函数指针调用约定

返回类型(调用约定 *变量名)(参数列表)

如:

int(_cdecl *pFun)(int,int);

int main(int argc, char* ar[])
{
	int(_stdcall *pFun)(int,int,int,int);
	pFun=(int(_stdcall *)(int,int,int,int))0x76A70660;
	MessageBox(0,0,0,0);
	MessageBox(0,0,0,0);
	pFun(0,0,0,0);
	return 0;
}
条件编译与文件包含
指令用途
#define定义宏
#undef取消已定义宏
#if如果给定条件为真,则编译下面代码
#elif如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
#else同else
#endif结束一个#if…#else条件编译块
#ifdef如果宏已经定义,则编译下面代码
#ifndef如果宏没有定义,则编译下面代码
#include包含文件

滴水PE开始作业笔记

什么是可执行文件

可执行文件 executable file指的是可以由操作系统进行加载执行的文件

可执行文件的格式:

Windows平台:

		PE(Portable Executable)文件结构

Linux平台:

		ELF(Executable and Linking Format)文件结构

解析PE文件

1 DOS头 struct _IMAGE_DOS_HEADER(64)
0x00 WORD e_magic;			//5A4D								*MZ标记用于判断是否为可执行文件
0x02 WORD e_cblp;			//0090
0x04 WORD e_cp;				//000
0x06 WORD e_crlc;			//0000
0x08 WORD e_cparhdr;		//0004
0x0a WORD e_minalloc;   	//0000
0x0c WORD e_maxalloc;   	//FFFF
0x0e WORD e_ss;				//0000
0x10 WORD e_sp;				//00B8
0x12 WORD e_csum;       	//0000
0x14 WORD e_ip;				//0000
0x16 WORD e_cs;         	//0000
0x18 WORD e_lfarlc;				//0040
0x1a WORD e_ovno;				//0000
0x1c WORD e_res[4];				//0000000000000000
0x24 WORD e_oemid;				//0000
0x26 WORD e_oeminfo;			//0000
0x28 WORD e_res2[10];			//0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xc DWORD e_lfanew;			//000000F8						*PE头相对于文件的偏移,用于定位PE文件

PE头标志(4):					//00005045

T头 struct _IMAGE_T_HEADERS 0xc DWORD e_lfanew;			
↓
标准PE头 struct _IMAGE_FILE_HEADER(20)
0x00 WORD Machine;								//014C			*程序运行的CPU型号:0x0任何处理器//0x14C 86及后续处理器
0x02 WORD umberOfSecti;						//0004			*文件中存在的节的总数,如果要新增节或者合并节 就要修改这个值
0x04 DWORD TimeDateStamp;						//4DCEB17D		*时间戳:文件的创建时间(和操作系统的创建时间无关),编译器填写的.
0x08 DWORD PointerToSymbolTable;				//00000000		
0x0c DWORD umberOfSymbols;						//00000000
0x10 WORD SizeOfOptionalHeader;					//00E0			*可选PE头的大小,2位PE文件默认E0h(16*14) 64位PE文件默认为F0h  大小可以自定义.
0x12 WORD Characteristics;						//010F			*每个位有不同的含义,可执行文件值为10F 即0 1 2  8位置1(特征勾选重定位信息、文件可执行、行号符号移去和2位机器是010F) 
( 用二进制从右至左看
  数据位	常量符号				      为1时的定义
	0  IMAGE_FILE_RELOCS_STRIPPED       	文件中不存在重定位信息
	1  IMAGE_FILE_EXECUTABLE_IMAGE			文件是可执行的
	2  IMAGE_FILE_LIE_UMS_STRIPPED		不存在行信息
	  IMAGE_FILE_LOCAL_SYMS_STRIPPED		不存在符号信息
	4  IMAGE_FILE_AGGRESSIVE_WS_TRIM		询整工作集
	5  IMAGE_FILE_LARGE_ADDRESS_AWARE		应用程序可处理大于 2GB 的地址
	6										此标志保留
	7  IMAGE_FILE_BYTES_REVERSED_LO			小尾方式
	8  IMAGE_FILE_2BIT_MACHIE				只在 2 位平台上运行
	9  IMAGE_FILE_DEBUG_STRIPPED			不但含调试信息
	10  IMAGE_FILE_REMOVABLE_RU_FROM_SWAP	不能从可移动盘运行
	11 IMAGE_FILE_ET_RU_FROM_SWAP			不能从网络运行
	12 IMAGE_FILE_SYSTEM					系统文件(如驱动程序),不能直接运行
	1 IMAGE_FILE_DLL						这是一个 DLL 文件
	14 IMAGE_FILE_UP_SYSTEM_OLY			文件不能在多处理器计算机上运行
	15 IMAGE_FILE_BYTES_REVERSED_HI			大尾方式
)


可选PE头 struct _IMAGE_OPTIOAL_HEADER(224)
0x00 WORD Magic;								//010B			*说明文件类型:10B 2位下的PE文件     20B 64位下的PE文件
0x02 BYTE MajorLinkerVersion;					//06
0x0 BYTE MinorLinkerVersion;					//00
0x04 DWORD SizeOfCode;							//00045000		*所有代码节的和,必须是FileAlignment的整数倍 编译器填的  没用
0x08 DWORD SizeOfInitializedData;				//00028000		*已初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的  没用
0x0c DWORD SizeOfUninitializedData;				//00000000		*未初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的  没用
0x10 DWORD AddressOfEntryPoint;(OEP)			//000441EC		*程序入口
0x14 DWORD BaseOfCode;							//00001000		*代码开始的基址,编译器填的   没用
0x18 DWORD BaseOfData;							//00046000		*数据开始的基址,编译器填的   没用
0x1c DWORD ImageBase;							//00400000		*****内存镜像基址
0x20 DWORD SectionAlignment;									*内存对齐 1000h
0x24 DWORD FileAlignment;										*文件对齐 200h
0x28 WORD MajorOperatingSystemVersion;
0x2a WORD MinorOperatingSystemVersion;
0x2c WORD MajorImageVersion;
0x2e WORD MinorImageVersion;
0x0 WORD MajorSubsystemVersion;
0x2 WORD MinorSubsystemVersion;
0x4 DWORD Win2VersionValue;
0x8 DWORD SizeOfImage;							//0006E000		*内存中整个PE文件的映射的尺寸,可以比实际的值大,但必须是SectionAlignment的整数倍
0xc DWORD SizeOfHeaders;										*所有头节表按照文件对齐后的大小,否则加载会出错
0x40 DWORD CheckSum;											*校验和,一些系统文件有要求.用来判断文件是否被修改.
0x44 WORD Subsystem;
0x46 WORD DllCharacteristics;
0x48 DWORD SizeOfStackReserve;									*初始化时保留的堆栈大小 
0x4c DWORD SizeOfStackCommit;									*初始化时实际提交的大小 
0x50 DWORD SizeOfHeapReserve;									*初始化时保留的堆大小 
0x54 DWORD SizeOfHeapCommit;									*初始化时实践提交的大小 
0x58 DWORD LoaderFlags;
0x5c DWORD umberOfRvaAndSizes;					//00000010
0x60 _IMAGE_DATA_DIRECTORY DataDirectory[16];

节表 _IMAGE_SECTIO_HEADER(在标准PE头umberOfSecti查看节的总数)
(.text节)(.data节)(.rsrc节)(.reloc节)(...)
0x00 BYTE ame[IMAGE_SIZEOF_SHORT_AME];		//0747865742E	*8个字节 一般情况下是以\0结尾的ASCII吗字符串来标识的名称,内容可以自定义.
union {
0x08 DWORD PhysicalAddress;
0x08 DWORD VirtualSize;
} Misc;(被干掉也不妨碍程序)						//000440A2		*双字 是该节在没有对齐前的真实尺寸,该值可以不准确。
0x0c DWORD VirtualAddress;						//00001000		*节区在内存中的偏移地址。加上ImageBase才是在内存中的真正地址.
0x10 DWORD SizeOfRawData;						//00045000		*节在文件中对齐后的尺寸.
0x14 DWORD PointerToRawData;					//00001000		*在文件中的偏移 开始地址(在文件中存在哪里)
0x18 DWORD PointerToRelocati;
0x1c DWORD PointerToLinenumbers;
0x20 WORD umberOfRelocati;
0x22 WORD umberOfLinenumbers;
0x24 DWORD Characteristics;										*节的属性(可读、可写、可执行)


读取PE头

#define _CRT_SECURE_O_WARIGS

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#define filepath  C:\\Users\\Administrator\\Desktop\\

LPVOID ReadPEFile(LPCSTR lpszFile);
VOID PrintTHeaders();
int main(int argc, char* ar[])
{

    PrintTHeaders();
    return 0;
}
LPVOID ReadPEFile(LPCSTR lpszFile)
{
    FILE* pFile = ULL;
    DWORD fileSize = 0;
    LPVOID pFileBuffer = ULL;
    //打开文件
    pFile = fopen(lpszFile, rb);
    if (!pFile)
    {
        printf(无法打开文件!\n);
        return ULL;
    }
    //读取文件大小
    fseek(pFile, 0, SEEK_ED);
    fileSize = ftell(pFile);
    fseek(pFile, 0, SEEK_SET);
    //开辟内存空间、分配缓冲区
    pFileBuffer = malloc(fileSize);
    if (!pFileBuffer)
    {
        printf(分配空间失败!\n);
        fclose(pFile);
        return ULL;
    }
    //将文件数据读取到缓冲区
    size_t n = fread(pFileBuffer, fileSize, 1, pFile);
    if (!n)
    {
        printf(读取数据失败!\n);
        free(pFileBuffer);
        fclose(pFile);
        return  ULL;
    }
    //关闭文件
    fclose(pFile);
    return pFileBuffer;
}

VOID PrintTHeaders()
{
    LPVOID pFileBuffer = ULL;
    PIMAGE_DOS_HEADER pDosHeader = ULL;
    PIMAGE_T_HEADERS ptHeaders = ULL;
    PIMAGE_FILE_HEADER pFileHeader = ULL;
    PIMAGE_OPTIOAL_HEADER pOpHeader = ULL;
    PIMAGE_SECTIO_HEADER pSeHeader = ULL;
    pFileBuffer = ReadPEFile(filepath);
    if (!pFileBuffer)
    {
        printf(文件读取失败!\n);
        return;
    }

    //判断是否是有效的MZ标志
    if ((*(PWORD)pFileBuffer) != IMAGE_DOS_SIGATURE)
    {
        printf(不是有效的MZ标志!\n);
        free(pFileBuffer);
        return;
    }
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    //以下要往前加位置才能往后读取
    //打印DOS头
    printf(**********DOS头**********\n);
    printf(MZ标志:%x\n, pDosHeader->e_magic);
    printf(PE偏移 定位PE:%x\n, pDosHeader->e_lfanew);
    //打印T头
    printf(**********T头**********\n);
    ptHeaders = (PIMAGE_T_HEADERS)((DWORD)pFileBufferpDosHeader->e_lfanew);
    printf(T头:%x\n, ptHeaders->Signature);
    //打印标准PE头
    pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)ptHeaders4);
    printf(Machine:%x\n, pFileHeader->Machine);
    printf(umberOfSecti:%x\n, pFileHeader->umberOfSecti);
    printf(TimeDateStamp:%x\n, pFileHeader->TimeDateStamp);
    printf(PointerToSymbolTable:%x\n, pFileHeader->PointerToSymbolTable);
    //打印可选PE头
    pOpHeader = (PIMAGE_OPTIOAL_HEADER)((DWORD)pFileHeader20);
    printf(Magic:%x\n,pOpHeader->Magic);
    printf(SizeOfCode:%x\n, pOpHeader->SizeOfCode);
    //释放内存
    free(pFileBuffer);
}


fopen()打开待读取的文件

r 打开只读文件,该文件必须存在
r 打开可读写的文件,该文件必须存在
rb 读写打开一个二进制文件,只允许读写数据
rt 读写打开一个文本文件,允许读和写
w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
w 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
a 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)
wb 只写打开或新建一个二进制文件;只允许写数据。
wb 读写打开或建立一个二进制文件,允许读和写。
wt 读写打开或着建立一个文本文件;允许读写。
at 读写打开一个文本文件,允许读或在文本末追加数据。
ab 读写打开一个二进制文件,允许读或在文件末追加数据。

fseek()用来读取文件流的读写位置

SEEK_ED 将读写位置指向文件末尾

SEEK_SET 将读写位置指向文件开头

SEEK_CUR 将读写位置指向当前位置

ftell()取得目前读写的位置

fread() fwrite() 将文件内容读取到内存

LPVOID 是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量,在使用的时候转换回来

BYTE char 1字节

WORD short 2字节

DWORD long 4字节

PWORD 是指向一个单词的指针,在2位下是4字节在64位下是8字节

size_t 用于表示对象的大小或数组的索引,是计算对象大小并存储,无符号整数类型,sizeof操作符返回的结果类型(通常用于:1、计算数组的长度或元素数量 2、在内存分配函数如malloc、calloc中表示分配的内存大小 、在函数参数中用作索引如memset、memcpy)

读取节表

#define _CRT_SECURE_O_WARIGS

//#include stdafx.h
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#define filepath  C:\\Users\\Administrator\\Desktop\\

LPVOID ReadPEFile(LPCSTR lpszFile);
void PrintTHeaders();
int main(int argc, char* ar[])
{

    PrintTHeaders();
    return 0;
}
LPVOID ReadPEFile(LPCSTR lpszFile)
{
    FILE* pFile = ULL;
    DWORD fileSize = 0;
    LPVOID pFileBuffer = ULL;
    //打开文件
    pFile = fopen(lpszFile, rb);
    if (!pFile)
    {
        printf(无法打开文件!\n);
        return ULL;
    }
    //读取文件大小
    fseek(pFile, 0, SEEK_ED);
    fileSize = ftell(pFile);
    fseek(pFile, 0, SEEK_SET);
    //开辟内存空间、分配缓冲区
    pFileBuffer = malloc(fileSize);
    if (!pFileBuffer)
    {
        printf(分配空间失败!\n);
        fclose(pFile);
        return ULL;
    }
    //将文件数据读取到缓冲区
    size_t n = fread(pFileBuffer, fileSize, 1, pFile);
    if (!n)
    {
        printf(读取数据失败!\n);
        free(pFileBuffer);
        fclose(pFile);
        return  ULL;
    }
    //关闭文件
    fclose(pFile);
    return pFileBuffer;
}

void PrintTHeaders()
{
    LPVOID pFileBuffer = ULL;
    PIMAGE_DOS_HEADER pDosHeader = ULL;
    PIMAGE_T_HEADERS ptHeaders = ULL;
    PIMAGE_FILE_HEADER pFileHeader = ULL;
    PIMAGE_OPTIOAL_HEADER pOpHeader = ULL;
    PIMAGE_SECTIO_HEADER pSeHeader = ULL;
    pFileBuffer = ReadPEFile(filepath);
    if (!pFileBuffer)
    {
        printf(文件读取失败!\n);
        return;
    }

    //判断是否是有效的MZ标志
    if ((*(WORD*)pFileBuffer) != IMAGE_DOS_SIGATURE)
    {
        printf(不是有效的MZ标志!\n);
        free(pFileBuffer);
        return;
    }
    pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
    //以下要往前加位置才能往后读取
    //打印DOS头
    printf(**********DOS头**********\n);
    printf(MZ标志:%x\n, pDosHeader->e_magic);
    printf(PE偏移 定位PE:%x\n, pDosHeader->e_lfanew);
    //打印T头
    printf(**********T头**********\n);
    ptHeaders = (PIMAGE_T_HEADERS)((DWORD)pFileBufferpDosHeader->e_lfanew);
    printf(T头:%x\n, ptHeaders->Signature);
    
    //打印标准PE头
    printf(**********标准PE头**********\n);
    pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)ptHeaders4);
    printf(Machine:%x\n, pFileHeader->Machine);
    printf(umberOfSecti:%x\n, pFileHeader->umberOfSecti);
    printf(TimeDateStamp:%x\n, pFileHeader->TimeDateStamp);
    printf(PointerToSymbolTable:%x\n, pFileHeader->PointerToSymbolTable);
    printf(SizeOfOptionalHeader:%x\n, pFileHeader->SizeOfOptionalHeader);
    //打印可选PE头
    printf(**********可选PE头**********\n);
    pOpHeader = (PIMAGE_OPTIOAL_HEADER)((DWORD)pFileHeader20);
    printf(Magic:%x\n,pOpHeader->Magic);
    printf(SizeOfCode:%x\n, pOpHeader->SizeOfCode);
    //打印节表
    pSeHeader = IMAGE_FIRST_SECTIO(ptHeaders);
    for (int i = 0; i < ptHeaders->FileHeader.umberOfSecti; i)
    {
        printf(**********第%d个节表**********\n, i  1);
        printf(ame:%.*s\n, IMAGE_SIZEOF_SHORT_AME, pSeHeader->ame);
        printf(VirtualSize:0x%.x\n, pSeHeader[i].Misc.VirtualSize);
        printf(VirtualAddress:0x%.x\n, pSeHeader[i].VirtualAddress);
        printf(SizeOfRawData:0x%.x\n, pSeHeader[i].SizeOfRawData);
        printf(PointerToRawData:0x%.x\n, pSeHeader[i].PointerToRawData);
        printf(PointerToRelocati:0x%.x\n, pSeHeader[i].PointerToRelocati);
        printf(PointerToLinenumbers:0x%.x\n, pSeHeader[i].PointerToLinenumbers);
        printf(umberOfRelocati:0x%.x\n, pSeHeader[i].umberOfRelocati);
        printf(umberOfLinenumbers:0x%.x\n, pSeHeader[i].umberOfLinenumbers);
        printf(Characteristics:0x%.x\n, pSeHeader[i].Characteristics);
    }
    //释放内存
    free(pFileBuffer);
}


#define _CRT_SECURE_O_WARIGS

//#include stdafx.h
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#define filepath  C:\\Users\\Administrator\\Desktop\\

LPVOID ReadPEFile(LPCSTR lpszFile);
void PrintTHeaders();
int main(int argc, char* ar[])
{
	PrintTHeaders();
	return 0;
}
LPVOID ReadPEFile(LPCSTR lpszFile)
{
	FILE* pFile = ULL;
	DWORD fileSize = 0;
	LPVOID pFileBuffer = ULL;
	//打开文件
	pFile = fopen(lpszFile, rb);
	if (!pFile)
	{
		printf(无法打开文件!\n);
		return ULL;
	}
	//读取文件大小
	fseek(pFile, 0, SEEK_ED);
	fileSize = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);
	//开辟内存空间、分配缓冲区
	pFileBuffer = malloc(fileSize);
	if (!pFileBuffer)
	{
		printf(分配空间失败!\n);
		fclose(pFile);
		return ULL;
	}
	//将文件数据读取到缓冲区
	size_t n = fread(pFileBuffer, fileSize, 1, pFile);
	if (!n)
	{
		printf(读取数据失败!\n);
		free(pFileBuffer);
		fclose(pFile);
		return  ULL;
	}
	//关闭文件
	fclose(pFile);
	return pFileBuffer;
}

void PrintTHeaders()
{
	LPVOID pFileBuffer = ULL;
	PIMAGE_DOS_HEADER pDosHeader = ULL;
	PIMAGE_T_HEADERS ptHeaders = ULL;
	PIMAGE_FILE_HEADER pFileHeader = ULL;
	PIMAGE_OPTIOAL_HEADER pOpHeader = ULL;
	PIMAGE_SECTIO_HEADER pSeHeader = ULL;
	pFileBuffer = ReadPEFile(filepath);
	if (!pFileBuffer)
	{
		printf(文件读取失败!\n);
		return;
	}

	//判断是否是有效的MZ标志
	if ((*(WORD*)pFileBuffer) != IMAGE_DOS_SIGATURE)
	{
		printf(不是有效的MZ标志!\n);
		free(pFileBuffer);
		return;
	}
	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	//以下要往前加位置才能往后读取
	//打印DOS头
	printf(**********DOS头**********\n);
	printf(MZ标志:%x\n, pDosHeader->e_magic);
	printf(PE偏移 定位PE:%x\n, pDosHeader->e_lfanew);
	//打印T头
	printf(**********T头**********\n);
	ptHeaders = (PIMAGE_T_HEADERS)((DWORD)pFileBuffer  pDosHeader->e_lfanew);
	printf(T头:%x\n, ptHeaders->Signature);

	//打印标准PE头
	printf(**********标准PE头**********\n);
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)ptHeaders  4);
	printf(Machine:%x\n, pFileHeader->Machine);
	printf(umberOfSecti:%x\n, pFileHeader->umberOfSecti);
	printf(TimeDateStamp:%x\n, pFileHeader->TimeDateStamp);
	printf(PointerToSymbolTable:%x\n, pFileHeader->PointerToSymbolTable);
	printf(SizeOfOptionalHeader:%x\n, pFileHeader->SizeOfOptionalHeader);
	//打印可选PE头
	printf(**********可选PE头**********\n);
	pOpHeader = (PIMAGE_OPTIOAL_HEADER)((DWORD)pFileHeader  20);
	printf(Magic:%x\n, pOpHeader->Magic);
	printf(SizeOfCode:%x\n, pOpHeader->SizeOfCode);
	printf(SizeOfHeaders:%x\n, pOpHeader->SizeOfHeaders);
	//打印节表
	//pSeHeader = IMAGE_FIRST_SECTIO(ptHeaders);
	pSeHeader = (PIMAGE_SECTIO_HEADER)((DWORD)pOpHeader  pFileHeader->SizeOfOptionalHeader);
	for (int i = 0; i < ptHeaders->FileHeader.umberOfSecti; i)
	{
		printf(**********第%d个节表**********\n, i  1);
		printf(ame:%.*s\n, IMAGE_SIZEOF_SHORT_AME, pSeHeader[i].ame);
		printf(VirtualSize:0x%.x\n, pSeHeader[i].Misc.VirtualSize);
		printf(VirtualAddress:0x%.x\n, pSeHeader[i].VirtualAddress);
		printf(SizeOfRawData:0x%.x\n, pSeHeader[i].SizeOfRawData);
		printf(PointerToRawData:0x%.x\n, pSeHeader[i].PointerToRawData);
		printf(PointerToRelocati:0x%.x\n, pSeHeader[i].PointerToRelocati);
		printf(PointerToLinenumbers:0x%.x\n, pSeHeader[i].PointerToLinenumbers);
		printf(umberOfRelocati:0x%.x\n, pSeHeader[i].umberOfRelocati);
		printf(umberOfLinenumbers:0x%.x\n, pSeHeader[i].umberOfLinenumbers);
		printf(Characteristics:0x%.x\n, pSeHeader[i].Characteristics);
	}

	//释放内存
	free(pFileBuffer);
}

RVA与FOA的转换

RVA:相对虚拟地址

FOA:文件偏移地址

1、得到RVA的值:内存地址-ImageBase

2、判断RVA是否位于PE头重,如果是:FOA==RVA

、判断RVA位于哪个节(条件必须同时成立的):

	RVA>=节.VirtualAddress

	RVA<=节.VirtualAddress节.VirtualSize

	差值A=RVA-节.VirtualAddress

	文件中的地址=差值APointRawData
RVA = 全局变量 - ImageBase
FOA:
1、判断RVA是否在头部 在的话直接返回
    FOA=RVA
2、如不在就判断这个值在哪个节里
		RVA>=.VirtualAddress
		RVA<=.VirtualAddress当前节内存对齐后的大小
		差值=RVA-.VirtualAddress
    	FOA=.PointerToRawData差值

PE加载的过程

1、根据SizeOfImage的大小,开辟一块缓冲区(ImageBuffer).

2、根据SizeOfHeader的大小,将头信息从FileBuffer拷贝到ImageBuffer

、根据节表中的信息循环讲FileBuffer中的节拷贝到ImageBuffer中.

4、Misc.VirtualSize 和 SizeOfRawData谁大?

5、FileBuffer与ImageBuffer谁大?

PE模拟exe加载到内存(FileBuffer-ImageBuffer)

#define _CRT_SECURE_O_WARIGS

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

//变量声明
PIMAGE_DOS_HEADER pDosHeader = ULL;
PIMAGE_T_HEADERS ptHeader = ULL;
PIMAGE_FILE_HEADER pFileHeader = ULL;
PIMAGE_SECTIO_HEADER pSeHeader = ULL;
PIMAGE_OPTIOAL_HEADER pOpHeader = ULL;

//exe文件地址
#define filepath  C:\\Users\\Administrator\\Desktop\\

DWORD ReadFile(LPVOID* pFileBuffer);
DWORD CopyFileBufferToImageBuffer(LPVOID ppFileBuffer, LPVOID* ppImageBuffer);
DWORD CopyImageBufferToFileBuffer(LPVOID pppImageBuffer, LPVOID* pppBuffer);
BOOL MemeryToFile(LPVOID ppppBuffer, DWORD SizeOfBuffer);
int main(int argc, char* ar[])
{
	LPVOID pFileBuffer = ULL;
	LPVOID* ppFileBuffer = &pFileBuffer;
	LPVOID pImageBuffer = ULL;
	LPVOID* ppImageBuffer = &pImageBuffer;
	DWORD SizeOfFileBuffer = 0;
	DWORD SizeOfImageBuffer = 0;
	DWORD SizeOfBuffer = 0;

	LPVOID pBuffer = ULL;
	LPVOID* ppBuffer = &pBuffer;

	//调用readFile
	SizeOfFileBuffer = ReadFile(ppFileBuffer);
	if (!SizeOfFileBuffer)
	{
		printf(调用ReadFile失败\n);
		return 0;
	}
	pFileBuffer = *ppFileBuffer;
	//调用CopyFileBufferToImageBuffer
	SizeOfBuffer = CopyFileBufferToImageBuffer(pFileBuffer, ppImageBuffer);
	if (!SizeOfBuffer)
	{
		printf(调用FileToImage失败!\n);
		return 0;
	}
	//调用CopyImageBufferToFileBuffer
	SizeOfBuffer = CopyImageBufferToFileBuffer(pImageBuffer, ppBuffer);
	pBuffer = *ppBuffer;
	if (!SizeOfBuffer)
	{
		printf(调用ImageToewFile失败!\n);
		return 0;
	}
	//调用MemeryToFile
	if (MemeryToFile(pBuffer, SizeOfBuffer) == FALSE)
	{
		printf(end\n);
		return 0;
	}
	return 0;
}

DWORD ReadFile(LPVOID* pFileBuffer)
{
	FILE* file;
	DWORD pFileSize = 0;

	//打开文件
	file = fopen(filepath, rb);
	if (!file)
	{
		printf(打开文件失败!\n);
		return 0;
	}
	//读取文件大小
	fseek(file, 0, SEEK_ED);
	pFileSize = ftell(file);
	fseek(file, 0, SEEK_SET);
	if (pFileSize == ULL)
	{
		printf(读取文件大小失败!\n);
		return 0;
	}
	//分配内存
	*pFileBuffer = malloc(pFileSize);
	if (!*pFileBuffer)
	{
		printf(分配内存失败!\n);
		fclose(file);
		return 0;
	}
	//将文件内容读取到缓冲区
	size_t n = fread(*pFileBuffer, pFileSize, 1, file);
	if (!n)
	{
		printf(复制数据失败!\n);
		fclose(file);
		free(*pFileBuffer);
		return 0;
	}
	fclose(file);
	return pFileSize;
}

DWORD CopyFileBufferToImageBuffer(LPVOID ppFileBuffer, LPVOID* ppImageBuffer)
{
	if (!ppFileBuffer)
	{
		printf(ppFileBuffer调用失败!\n);
		return 0;
	}
	printf(CopyFileBufferToImageBuffer里ppFileBuffer刚开始的值:%p\n, ppFileBuffer);
	//判断是否是PE文件
	pDosHeader = (PIMAGE_DOS_HEADER)ppFileBuffer;
	if (pDosHeader->e_magic != IMAGE_DOS_SIGATURE)
	{
		printf(不是有效的MZ标志!\n);
		return 0;
	}
	ptHeader = (PIMAGE_T_HEADERS)((DWORD)ppFileBuffer  pDosHeader->e_lfanew);
	if (ptHeader->Signature != IMAGE_T_SIGATURE)
	{
		printf(不是有效的PE标志!\n);
		return 0;
	}
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)ptHeader  4);
	pOpHeader = (PIMAGE_OPTIOAL_HEADER)((DWORD)pFileHeader  20);
	//开辟空间
	*ppImageBuffer = malloc(pOpHeader->SizeOfImage);
	if (!*ppImageBuffer)
	{
		printf(CopyFileBufferToImageBuffer开辟imagebuffer空间失败!\n);
		return 0;
	}
	//将内存清零
	memset(*ppImageBuffer, 0, pOpHeader->SizeOfImage);
	//复制数据
	memcpy(*ppImageBuffer, pDosHeader, pOpHeader->SizeOfHeaders);
	//循环复制节表
	pSeHeader = (PIMAGE_SECTIO_HEADER)((DWORD)pOpHeader  pFileHeader->SizeOfOptionalHeader);
	for (int i = 1; i <= pFileHeader->umberOfSecti; i, pSeHeader)
	{
		memcpy((LPVOID)((DWORD)*ppImageBuffer  pSeHeader->VirtualAddress), (LPVOID)((DWORD)ppFileBuffer  pSeHeader->PointerToRawData), pSeHeader->SizeOfRawData);
		printf(%d\n, i);
	}
	printf(CopyFileBufferToImageBuffer拷贝成功!\n);
	return pOpHeader->SizeOfImage;
}

DWORD CopyImageBufferToFileBuffer(LPVOID pppImageBuffer, LPVOID* pppBuffer)
{
	if (!pppImageBuffer)
	{
		printf(调用pppImageBuffer失败!\n);
		return 0;
	}
	pDosHeader = (PIMAGE_DOS_HEADER)pppImageBuffer;
	ptHeader = (PIMAGE_T_HEADERS)((DWORD)pppImageBuffer  pDosHeader->e_lfanew);
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)ptHeader  4);
	pOpHeader = (PIMAGE_OPTIOAL_HEADER)((DWORD)pFileHeader  20);
	pSeHeader = (PIMAGE_SECTIO_HEADER)((DWORD)pOpHeader  pFileHeader->SizeOfOptionalHeader);

	//得到FileBuffer的大小
	for (int i = 1; i < pFileHeader->umberOfSecti; i, pSeHeader)
	{
		printf(%d\n, i);
	}
	//循环到最后一个节表
	DWORD SizeOfBuffer = pSeHeader->PointerToRawData  pSeHeader->SizeOfRawData;
	//开辟空间
	*pppBuffer = malloc(SizeOfBuffer);
	if (!*pppBuffer)
	{
		printf(开辟buffer空间失败!\n);
		return 0;
	}
	//缓冲区清零
	memset(*pppBuffer, 0, SizeOfBuffer);

	memcpy(*pppBuffer, pppImageBuffer, pOpHeader->SizeOfHeaders);
	//循环复制节表
	pSeHeader = (PIMAGE_SECTIO_HEADER)((DWORD)pOpHeader  pFileHeader->SizeOfOptionalHeader);
	for (int j = 1; j <= pFileHeader->umberOfSecti; j, pSeHeader)
	{
		memcpy((LPVOID)((DWORD)*pppBuffer  pSeHeader->PointerToRawData), (LPVOID)((DWORD)pppImageBuffer  pSeHeader->VirtualAddress), pSeHeader->SizeOfRawData);
		printf(%d\n, j);
	}
	printf(CopyImageBufferToFileBuffer拷贝成功!\n);
	return SizeOfBuffer;
}

BOOL MemeryToFile(LPVOID ppppBuffer, DWORD SizeOfBuffer)
{
	FILE* file = fopen(C:\\Users\\Administrator\\Desktop\\, wb);
	if (!file)
	{
		printf(file error\n);
		return 0;
	}
	if (fwrite(ppppBuffer, 1, SizeOfBuffer, file) == 0)
	{
		printf(file fwrite fail\n);
		return 0;
	}
	fclose(file);
	file = ULL;
	printf(success\n);
	return TRUE;
}

硬编码

代码节空白区添加代码(文件注入)
MessageBoxA:0x76780660

       Function();
0040D478 E8 8D B FF FF       call        @ILT5(Function) (0040100a)
       //MessageBox(0,0,0,0);
       return 0;
0040D47D  C0                xor         eax,eax


E9 01 00 00 00       jmp         Function (00401010)

CALL真正要跳转的地址 = E8这条指令的下一行地址  X			
			
X = 真正要跳转的地址0040100a - E8这条指令的下一行地址0040D47D			= 8DBFFFF

X = 401010 - 40100F = 1 (JMP就是E9 01)

要跳转的地方 = E8当前的地址  5  X

X = 要跳转的地址 - (E8的地址  5)



---------------------------------------------------------------------
(放在任意一个节后面的空白区)
6A 00 6A 00 6A 00 6A 00 (MeassageBoxA的硬编码push函数)
E8 00 00 00 00 E9 00 00 00 00 (call地址消息函数)
E8 00 00 00 00 后面0是填dbg到的MeassageBoxA基址-E8最后一个00后一位的地址
E9 00 00 00 00 后面0是填(EntryPointimagebase)-(E9最后一个00的地址)
最后把原来EntryPoint改成从什么地址开始添加的代码就改成什么地址
call = E8
jmp = E9
push = 6A

KR笔记

cl /c  产生.obj文件

.obj就是产生的代码支撑、数据支撑,二进制代码的中间文件,可以交给其他的编译器使用

link  产生.exe可执行文件

#include <stdio.h> <>尖括号仅是环境变量 双引号是当前目录

存进去的地址从左至右是从高位置到低位置,就是小段方式
#include <stdio.h>
#include 

int main(int argc, char *ar[])
{
	int n = 999;
	printf(Hello, world:%p:%d\n,&n,n);
	foo();
	
	getchar();
	return 0;
}

随机数 反码、补码
#define _CRT_SECURE_O_WARIGS

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>

int main(int argc, char* ar[])
{
	int n = 0;
	srand((unsigned)time(ULL));
	while (n < 10)
	{
		printf(%d\r\n, rand());
		n;
	}
	return 0;
}

为什么到80000000出来了?

#define _CRT_SECURE_O_WARIGS

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char* ar[])
{
	int n = 1;
	while (n > 0)
	{
		n;
	}
	printf(%x\r\n, n);
	return 0;
}

求补运算是一种运算

补码是一种编码

补码规定了数据的读写双方必须做到以下几点

1、最高有效位是符号位,0表示正、1表示负

2、当数据是正数的时候,其余各位直接存储其数值

、当数据为负数的时候,其余各位存储其求补后的值

#define _CRT_SECURE_O_WARIGS

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char* ar[])
{
	int n = 52;
	int m = -52;
    
	printf(%x\r\n, &n);
	return 0;
}

52
110100 最高位补位后
00110100
看成2进制就是
0011 0100
4在内存中就是4 00 00 00

-52

-52 的二进制表示可以通过以下步骤得到:

  1. 首先,将 52 的绝对值转换为二进制。
  2. 然后,将得到的二进制数取反,得到其反码。
  3. 最后,将得到的反码加 1,得到补码。

首先,52 的绝对值为 00110100(因为 52 的二进制表示为 00110100)。

然后,将其取反得到其反码:11001011。

最后,将得到的反码加 1。这一步骤是为了确保补码的符号位正确表示负数。在二进制补码表示中,最高位(即最左边的位)表示符号位。如果是负数,符号位为 1;如果是正数,符号位为 0。因此,将反码加 1 可以确保符号位正确。在这种情况下,11001011 加 1 为 11001100。

所以,-52 的二进制表示为 11001100。

CC 00 00 00

#include <stdio.h>

int main(int argc, char *ar[])
{
	//6, -6
	
	//0x86单字节有符号数的十进制真值是什么?
	//10000110
	//1 0000110
	//- 1111001 取反1
	//- 1111010
	// 0111 1010
	//	7	 A
	//7A=7*1610=-122
	
	//0x80呢?
	//1000 0000
	//-0111 1111 取反1
	//-10000000 = -128
	
	return 0;
}
异常报错笔记
C05:内存访问异常:访问了保留地址、或不存在的地址、或没有权限的地址
Scanf 用户输出
#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char* ar[])
{
	//一定要对变量进行初始化,否则上次用n变量的还会有残留数据
	int i1 = 0;
	char c1 = 	\0	;
	float f1 = 0.0f;
	double d1 = 0.0;
	char name[10] = { 0 };
	int* lpTest = ULL;

	char szBuf[20] = { 0 };
	//写长度不要造成越界,不然很容易被攻击
	//scanf(%s, szBuf, 20);

	//short int ary[2] = { 666,999 };
	//printf(%x\n, &ary[0]);
	//scanf(%d, ary);

	/*随堂作业*/
	//int n = 0x19FEF4;
	//int m = 0;
	//scanf(%d,n); //输入999
	//printf(%08x\r\n,n); //00000e7
	//printf(%08x\r\n,m); //00000000


	//等号左边必须是一个变量
	char ch1=	a	;
	char ch2=	b	;
	char ch=	c	;
	char ch4=	d	;

	printf(%p:%d\r\n,&ch1,sizeof(ch1));
	printf(%p:%d\r\n,&ch2,sizeof(ch2));



	system(pause);
	return 0;
}

**程序效率高不高跟语言没关系,和写程序的人有关系,人决定8成以上,剩下看编译器

循环结构、递归

99乘法表

#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char* ar[])
{
	for (int i = 1;i<=9;i)
	{
		for (int j = 1;j<=i;j)
		{
			printf(%d*%d=%d ,j,i,i*j);
		}
		printf(\n);
	}
	
	system(pause);
	return 0;
}

四角星作业

#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*
	6		 *
	5	   *   *
	4	*		 *
	 *			   *
	2	*		 *
	1	   *   *	
	0        *
	  0 1 2  4 5 6

	ax  c = y

	0a  c = 
	a  c = 6
	c = 
	a = 1
	x   == y

	a  c = 6
	6a  c = 
	a = -1
	c = 9
	-x  9 == y

	6a  c = 
	a  c = 0
	a = 1
	c = -
	x -  == y

	a  c = 0
	0a  c = 
	a = -1
	c = 
	-x   == y

	*/
int main(int argc, char* ar[])
{
	
	int x = 0;
	int y = 0;
	for (x = 0;x < 7; x)
	{
		for (y = 0;y < 7;y)
		{
			if (x   == y || -x  9 == y || x -  == y || -x   == y)
			{
				printf(* );
			}
			else
			{
				printf(  );
			}
		}
		printf(\n);
	}

	system(pause);
	return 0;
}  
地址			指令的内容			指令	
0040107 	5F                   pop         edi
0040108 	5E                   pop         esi
0040109 	5B                   pop         ebx
004010A 	8 C4 40             add         esp,40h
004010D 	B EC                cmp         ebp,esp
004010F 	E8 2C 0 00 00       call        __chkesp (0040170)
00401044 	8B E5                mov         esp,ebp
00401046 	5D                   pop         ebp

if…else 可以控制命中率

switch…case 最好是大于个分支在用

#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


int main(int argc, char* ar[])
{
	int n = ;
	
	/*if(n == 1)
	{
		printf(n == 1\n);
	}
	else if (n == 2)
	{
		printf(n == 2\n);
	}
	else if (n == )
	{
		printf(n == \n);
	}
	else if (n == 4)
	{
		printf(n == 4\n);
	}
	*/

	switch(n)
	{
	case 0:
		printf(%d\n,n);
		break;
	case 1:
		printf(%d\n,n);
		break;
	case 2:
		printf(%d\n,n);
		break;
	case :
		printf(%d\n,n);
		break;
	case 4:
		printf(%d\n,n);
		break;

	}


	system(pause);
	return 0;
}  
#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <MATH.H>




int main(int argc, char* ar[])
{
	int n = 15000;
	double  nBitCount = 0.0;
	int i = 1;

	
	for (int i = 1; i <= n; i)
	{
		nBitCount = log10(i);
	}
	/*
DO_BEGI:
	nBitCount = log10(i);
	i;
	if (i<=n)
	{
		goto DO_BEGI;
	}*/

	//ceil函数用于向上取整,即使不小于参数的最小整数,例如ceil(4.),ceil(4.7)也将返回5
	printf(%d\n,(int)ceil(nBitCount));

	system(pause);
	return 0;
} 
#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <MATH.H>




int main(int argc, char* ar[])
{
	int nHp = 0;

	srand( (unsigned)time( ULL ) );
	while(nHp<100)
	{
		int nFood = rand()%100;
		if (nFood<1000)
		{
			printf(吃了一口,体力恢复5\r\n);
			nHp=5;
		}
		else if (nFood>=700 && nFood <850)
		{
			printf(吃了一口蔬菜,体力恢复10\r\n);
			nHp=10;
		}
		else if (nFood>=850 && nFood <950)
		{
			printf(吃了一口肉,体力恢复20\r\n);
			nHp=20;
		}
		else if (nFood>=950 && nFood <980)
		{
			printf(吃到头发不吃了\r\n);
			continue;
		}
		else if (nFood>=980 && nFood <999)
		{
			printf(吃到蟑螂不吃了!\r\n);
			break;
		}

		if (nFood>=1000)
		{
			printf(吃饱了,下次来\r\n);
		}
		else if (nHp<0)
		{
			printf(没吃饱\r\n);
		}
		else
		{
			printf(太恶心了 报警\r\n);
		}
	}
	
 

	system(pause);
	return 0;
} 

判断是否是质数

#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <MATH.H>




int main(int argc, char* ar[])
{
	
	
	for (int n = 2;n<=100;n)
	{
		int isPrime = 1;
		//sqrt是返回一个平方根
		for (int i = 2; i < (int)sqrt(n)1;i)
		{
			if (n%i==0)
			{
				isPrime=0;
				break;
			}
		}

		
		if (isPrime)
		{
			printf(%d ,n);
		}
	}			



	system(pause);
	return 0;
} 
#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <MATH.H>




int main(int argc, char* ar[])
{
	int n = 100;
	if (n<1)
	{
		//error info
		return -1;
	}
	printf(sum(%d) = %d \r\n,n,(1n)*(n/2));
	
	system(pause);
	return 0;
} 

猴子吃桃

#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <MATH.H>




int main(int argc, char* ar[])
{
	int nCount = 1;
	for (int i =0;i<9;i)
	{
		nCount=(nCount1)*2;
	}
	printf(%d\r\n,nCount);
	
	system(pause);
	return 0;
} 

斐波那契数列(每一项都是前两项的和)

#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <MATH.H>


int DiGuiFib(int n)
{
	if (n==1||n==2)
	{
		return 1;
	}

	return DiGuiFib(n-2)DiGuiFib(n-1);
}


int main(int argc, char* ar[])
{
	/* 斐波那契数列数组循环
	int arr[50]={1,1};
	for (int i = 2;i < 40;i)
	{
		arr[i]=arr[i-1]arr[i-2];
		printf(%-15u%f\r\n,arr[i],(double)arr[i-1]/arr[i]);
	}
	*/

	int nFib1 = 1;
	int nFib2 = 1;
	int nFib = 0;

	for (int i = 2;i < 47;i)
	{
		nFib1=(double)DiGuiFib(i-1);
		nFib2=DiGuiFib(i);
		printf(%-15u%f\r\n,nFib2,(double)nFib1/nFib2);
	}

	
	system(pause);
	return 0;
} 

函数调用

#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <MATH.H>


int DiGuiFib(int n)
{
	int nFib1 = 1;
	int nFib2 = 1;
	int nFib = 0;
	if (n==1||n==2)
	{
		return 1;
	}

	for (int i = 2;i<=n;i)
	{
		nFib=nFib1nFib2;
		nFib1=nFib2;
		nFib2=nFib;
	}

	return nFib;
}


int main(int argc, char* ar[])
{
    unsigned int nFib1 = DiGuiFib(1);
	unsigned int nFib2 = DiGuiFib(1);
	
	for (int i = 2;i < 47;i)
	{
		nFib1=DiGuiFib(i);
		printf(%-15u%f\r\n,nFib1,(double)nFib2/nFib1);
		nFib2=nFib1;
	}
	
	system(pause);
	return 0;
} 

函数调用约定

描述的地方:函数和返回值之间,默认是cdecl调用约定

1、调用约定:调用方(caller)需要和被调方(callee)作出以下约定: 01 00 00 00 传参
1.参数的传递方向
2.参数的传输媒介(栈传参、寄存器传参)
.函数返回值的位置
4.释放参数空间的负责方,有且仅有一方去释放参数空间

​ __cdecl:参数使用栈空间传递,从右往左传递,函数返回值在寄存器,由调用方负责释放参数空间

​ __stdcall:参数使用栈空间传递,从右往左传递,函数返回值在寄存器,由被调用方负责释放参数空间

​ __fastcall:左数前两个参数使用寄存器传递,其他参数使用栈空间传递,从右往左传递,函数返回值在寄存器,由被调用方负责释放参数空间

2、保存返回地址:在函数调用时,需要将下一条指令的地址(即返回地址)保存在栈上,以便在函数执行结束后返回到调用方 19 15 40 00

、保存调用方的栈信息(栈底) 在开始执行被调用函数之前,需要保存调用方的栈信息,即栈底的地址 70 FF 19 00

4、更新当前栈到栈顶(把当前栈顶作为被调方的栈底) 将当前栈顶作为被调用方的栈底,以便在函数执行期间分配局部变量空间70 FF 19 00

5、为局部变量申请空间(抬高栈顶) 在栈上为函数的局部变量分配内存空间 CCCCCCCCCCCC …

6、保存寄存器环境(把即将使用的寄存器原值保存在栈里) 如果函数需要使用寄存器来存储临时变量或者函数参数,那么在函数调用前需要保存这些寄存器的原值

*7、如果编译选项有/ZI /Zi (带调试信息),则将局部变量初始化为如果编译选项中包含调试信息,则局部变量可能会被初始化为特定的值(例如 0xCCCCCCCC)0xCCCCCCCC

8、执行函数体 执行函数的实际代码逻辑。

9、恢复寄存器环境 在函数执行结束后,需要将之前保存的寄存器值恢复到原始状态。

10、释放局部变量的空间 在函数执行结束后,需要释放为局部变量分配的内存空间。

11、恢复调用方的栈信息(栈底) 在函数执行结束后,需要将保存的调用方栈信息恢复,即将栈底的地址恢复到之前保存的值。

12、

12A、如果是__cdecl,取出当前栈顶作为返回的流程地址,返回到调用方后,由调用方清理参数空间

12B、 其他约定,取出当前栈顶作为返回的流程地址,同时由被调方清理参数空间后才返回

E 10 40 00 01 00 00 00 00 00 00 00 0 00 00 00 0 14 40 00 0 14 40 00 00 10 2E 00
CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC 
70 FF 19 00 19 15 40 00 01 00 00 00 28 1C 85 00 B0 1C 85 00

01 00 00 00:命令行个数(字符型指针数组)

28 1C 85 00:命令行列表(字符型指针数组)

B0 1C 85 00:环境变量列表(整型)

19 15 40 00:main函数的返回地址

70 FF 19 00:main函数调用方的栈信息,同时也是栈底,访问局部变量以这个地址作减法访问,访问参数是加法

CCC…:申请的局部变量空间

0 14 40 00 0 14 40 00 00 10 2E 00:保存的寄存器空间

code
dataInited常量区
可读可写区
Uninit
stack
heap

微软C/C编译器选项

-优化-
/O1最小化空间minimize space
/Op[-]改善浮点数一致性improve floating-pt cistency
/O2最大化速度maximize speed
/Os优选代码空间favor code space
/Oa假设没有别名assume no aliasing
/Ot优选代码速度favor code speed
/Ob内联展开(默认 n=0)inline expansion (default n=0)
/Ow假设交叉函数别名assume cross-function aliasing
/Od禁用优化(默认值)disable optimizati (default)
/Ox最大化选项。(/Ogityb2 /Gs)maximum opts. (/Ogityb1 /Gs)
/Og启用全局优化enable global optimization
/Oy[-]启用框架指针省略enable frame pointer omission
/Oi启用内建函数enable intrinsic functi
-代码生成-
/G为 8086 进行优化optimize for 8086
/G4为 80486 进行优化optimize for 80486
/GR[-]启用 C RTTIenable C RTTI
/G5为 Pentium 进行优化optimize for Pentium
/G6为 Pentium Pro 进行优化optimize for Pentium Pro
/GX[-]启用 C 异常处理(与 /EHsc 相同)enable C EH (same as /EHsc)
/EHs启用同步 C 异常处理enable synchronous C EH
/GD为 Windows DLL 进行优化optimize for Windows DLL
/GB为混合模型进行优化(默认)optimize for blended model (default)
/EHa启用异步 C 异常处理enable asynchronous C EH
/Gd__cdecl 调用约定__cdecl calling convention
/EHcextern“C”默认为 nothrowextern “C” defaults to nothrow
/Gr__fastcall 调用约定__fastcall calling convention
/Gi[-]启用增量编译enable incremental compilation
/Gz__stdcall 调用约定__stdcall calling convention
/Gm[-]启用最小重新生成enable minimal rebuild
/GA为 Windows 应用程序进行优化optimize for Windows Application
/Gf启用字符串池enable string pooling
/QIfdiv[-]启用 Pentium FDIV 修复enable Pentium FDIV fix
/GF启用只读字符串池enable read-only string pooling
/QI0f[-]启用 Pentium 0x0f 修复enable Pentium 0x0f fix
/Gy分隔链接器函数separate functi for linker
/GZ启用运行时调试检查enable runtime debug checks
/Gh启用钩子函数调用enable hook function call
/Ge对所有函数强制堆栈检查force stack checking for all funcs
/Gs[num]禁用堆栈检查调用disable stack checking calls
-输出文件-
/Fa[file]命名程序集列表文件name assembly listing file
/Fo命名对象文件name object file
/FA[sc]配置程序集列表configure assembly listing
/Fp命名预编译头文件name precompiled header file
/Fd[file]命名 .PDB 文件name .PDB file
/Fr[file]命名源浏览器文件name source browser file
/Fe命名可执行文件name executable file
/FR[file]命名扩展 .SBR 文件name extended .SBR file
/Fm[file]命名映射文件name map file
-预处理器-
/FI命名强制包含文件name forced include file
/C不吸取注释don’t strip comments
/U移除预定义宏remove predefined macro
/D{=|#}定义宏define macro
/u移除所有预定义宏remove all predefined macros
/E将预处理定向到标准输出preprocess to stdout
/I添加到包含文件的搜索路径add to include search path
/EP将预处理定向到标准输出,不要带行号preprocess to stdout, no #line
/X忽略“标准位置”ignore “standard places”
/P预处理到文件preprocess to file
-语言-
/Zi启用调试信息enable debugging information
/Zl忽略 .OBJ 中的默认库名omit default library name in .OBJ
/ZI启用调试信息的“编辑并继续”功能enable Edit and Continue debug info
/Zg生成函数原型generate function prototypes
/Z7启用旧式调试信息enable old-style debug info
/Zs只进行语法检查syntax check only
/Zd仅要行号调试信息line number debugging info only
/vd{0|1}禁用/启用 vtordispdisable/enable vtordisp
/Zp[n]在 n 字节边界上包装结构pack structs on n-byte boundary
/vm指向成员的指针类型type of pointers to members
/Za禁用扩展(暗指 /Op)disable extensi (implies /Op)
/noBool禁用“bool”关键字disable “bool” keyword
/Ze启用扩展(默认)enable extensi (default)
- 杂项 -
/?, /help打印此帮助消息print this help message
/c只编译,不链接compile only, no link
/W设置警告等级(默认 n=1)set warning level (default n=1)
/H最大化外部名称长度max external name length
/J默认 char 类型是 unsigneddefault char type is unsigned
/nologo取消显示版权消息suppress copyright message
/WX将警告视为错误treat warnings as errors
/Tc将文件编译为 .ccompile file as .c
/Yc[file]创建 .PCH 文件create .PCH file
/Tp将文件编译为 .cppcompile file as .cpp
/Yd将调试信息放在每个 .OBJ 中put debug info in every .OBJ
/TC将所有文件编译为 .ccompile all files as .c
/TP将所有文件编译为 .cppcompile all files as .cpp
/Yu[file]使用 .PCH 文件use .PCH file
/V设置版本字符串set version string
/YX[file]自动的 .PCH 文件automatic .PCH
/w禁用所有警告disable all warnings
/Zm最大内存分配(默认为 %)max memory alloc (% of default)
-链接-
/MD与 MSVCRT.LIB 链接link with MSVCRT.LIB
/MDd与 MSVCRTD.LIB 调试库链接link with MSVCRTD.LIB debug lib
/ML与 LIBC.LIB 链接link with LIBC.LIB
/MLd与 LIBCD.LIB 调试库链接link with LIBCD.LIB debug lib
/MT与 LIBCMT.LIB 链接link with LIBCMT.LIB
/MTd与 LIBCMTD.LIB 调试库链接link with LIBCMTD.LIB debug lib
/LD创建 .DLLCreate .DLL
/F设置堆栈大小set stack size
/LDd创建 .DLL 调试库Create .DLL debug libary
/link[链接器选项和库][linker opti and libraries]
经典题目:迷宫

0x00000000FD:栈溢出

project settings----link----Reserve(保留值,能用的空间)改为0x10000000 Commit(提交值,现在给你用的空间)改为0x01000000

#define _CRT_SECURE_O_WARIGS

#include StdAfx.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <MATH.H>
#include <STDLIB.H>

/*
随堂作业:迷宫

$终点,1表示墙,0表示路
*/
void Show(char szMaze[][1],int nRow)
{
	for (int i = 0;i<nRow;i)
	{
		puts(szMaze[i]);
	}

	return;
}

void Maze(char szMaze[][1],int x,int y)
{
	
	system(cls);
	Show(szMaze,8);
	system(pause);

	if (szMaze[x][y]==	$	)
	{
		printf(过关!\r\n);
		system(pause);
		exit(0);
	}
	//走过的地方设标志
	szMaze[x][y]=	\x1	;

	if (szMaze[x1][y]==	0	||szMaze[x1][y]==	$	)
	{
		Maze(szMaze,x1,y);
	}

	if (szMaze[x][y1]==	0	||szMaze[x][y1]==	$	)
	{
		Maze(szMaze,x,y1);
	}

	if (szMaze[x][y-1]==	0	||szMaze[x][y-1]==	$	)
	{
		Maze(szMaze,x,y-1);
	}

	if (szMaze[x-1][y]==	0	||szMaze[x-1][y]==	$	)
	{
		Maze(szMaze,x-1,y);
	}

	//走过的地方设标志
	szMaze[x][y]=	\x2	;

	system(cls);
	Show(szMaze,8);
	system(pause);

	return;
	
}

int main(int argc, char* ar[])
{
	char szMaze[][1] = {
		111111111111,
		1010000001$1,
		101011011101,
		101000011101,
		101011011101,
		100011011101,
		100011000001,
		111111111111,
	};


	Show(szMaze,8);
	Maze(szMaze,1,1);
	
	return 0;
} 
数组

强内聚,低耦合

强内聚:指模块或组件内部各部分之间功能联系紧密,完成单一任务或目标的程度。在强内聚的模块中,相关功能应该彼此关联,并且一致地服务于某一目标。强内聚的模块通常具有更好的可维护性、可重用性和可理解性,因为其功能单一、清晰明确。

低耦合:指模块或组件之间的依赖关系较弱,彼此之间的联系较少、相对独立。低耦合的设计使得系统中的各个部分能够更灵活、更容易地独立修改、测试、重用和理解。通过降低模块之间的耦合性,可以减少对系统的修改造成的影响范围,并且提高系统的可扩展性和可维护性。

常见的就是:界面和逻辑分离、业务和算法分离

寻址公式:(int)arr  sizeof(type)*n

#define _CRT_SECURE_O_WARIGS

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdlib.h>

void foo(int arr[5])
{
	//n;
	//arr;
	/*int temp = 0;
	printf(%d %d\r\n, x, y);
	temp = x;
	x = y;
	y = temp;
	建议不用
		x = x  y;
	y = x - y;
	x = x - y;

	printf(%d %d\r\n, x, y);*/

	int temp = arr[0];
	arr[0] = arr[1];
	arr[1] = temp;
}

int main() {
	int arr[5] = { 1,2,,4,5 };
	/*
		连续且一致
		第0个元素的地址常量
		int n = .....;
		type arr[M] = ....;
		arr[n] address;
			(int)arr  sizeof(type)*n

	*/
	int n = 2;
	//printf(%p\r\n, &arr[]); //4
	//printf(%p\r\n, (int)arr  sizeof(int) * );
	//printf(%p\r\n, &arr[n]); //
	//printf(%p\r\n, &arr[n - ]); //下标越界的地址
	//printf(%p\r\n, &arr[n  ]); //下标越界的地址
	//printf(%p\r\n, &n[arr]); //

	//printf(%p\r\n, arr[(0x00400000 - (int)arr) / sizeof(int)]);

	//foo();
	//foo(arr);
	int m = 5;
	foo(arr);

	return 0;
}
二维数组

寻址公式

	//多维数组是特殊的一维数组
	//维数组的元素是-1维数组
	// (int)arr  sizeof(type[][M]) * x   sizeof(type) * y //&arr[x] //&arr[x][y]
	// 等于下面的
	// (int)arr  sizeof(type[M]) * x   sizeof(type) * y
	// 推导
	//(int)arr  sizeof(type) * M * x  sizeof(type) * y
	//(int)arr  sizeof(type)*(M*xy)
#define _CRT_SECURE_O_WARIGS

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdlib.h>

// 能适用所有的二维数组(整型)
void ShowArr(int arr[], int nMaxX, int nMaxY)
{
	for (int i = 0; i < nMaxX; i)
	{
		for (int j = 0; j < nMaxY; j)
		{
			printf(%d\t, arr[nMaxY * i  j]);
		}
		printf(\r\n);
	}
}

// 常量阶
// 线性阶
// 指数阶
// 对数阶
int main() {
	//多维数组是特殊的一维数组
	//维数组的元素是-1维数组
	// (int)arr  sizeof(type[][M]) * x   sizeof(type) * y //&arr[x] //&arr[x][y]
	// 等于下面的
	// (int)arr  sizeof(type[M]) * x   sizeof(type) * y
	// 推导
	//(int)arr  sizeof(type) * M * x  sizeof(type) * y
	//(int)arr  sizeof(type)*(M*xy)
	int arr[][5] =
	{
		{1,2,,4,5},
		{2,2,,4,5},
		{,2,,4,5}
	};
	/*int arr[][4] =
	{
		{1,2,,4},
		{2,2,,4},
		{,2,,4}
	};*/

	ShowArr(&arr[0][0], , 5);

	int x = 2;
	int y = ;

	printf(%p\r\n, &arr[x][y]);
	printf(%p\r\n, (int)arr  sizeof(int[5]) * x  sizeof(int) * y);
	printf(%p\r\n, (int)arr  sizeof(int) * (5 * x  y));

	return 0;
}
#define _CRT_SECURE_O_WARIGS

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdlib.h>

//自己实现的标准库函数strcpy
void MyStrCpy(char szBuf[], ct char szSrc[])
{
	int i = 0;
	while (szSrc[i] != 	\0	)
	{
		szBuf[i] = szSrc[i];
		i;
	}
	szBuf[i] = 	\0	;

	//第二种写法,可读性太差
	//while (szBuf[i] = szSrc[i]);
}

int main() {
	char szBuf[20];
	MyStrCpy(szBuf, hello,world);
	printf(%s\n, szBuf);
	return 0;
}
作用域
#define _CRT_SECURE_O_WARIGS

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

int IsSplit(char ch)
{
	char arrSplit[] = { 	,	,	.	,	 	,	\n	,	-	 };
	for (int i = 0; i < sizeof(arrSplit); i)
	{
		if (ch == arrSplit[i])
		{
			return 1;
		}
	}
	return 0;
}

int main() {
	char szBuf[] = I like C,and Java.ha-ha\nwhat a u like?   ;
	int isSplit = 1;
	int isCount = 0;
	size_t nLength = strlen(szBuf);
	for (int i = 0; i < nLength; i)
	{
		if (!isSplit && IsSplit(szBuf[i]))
		{
			isSplit = 1;
		}

		//判断有几组单词
		if (isSplit && !IsSplit(szBuf[i]))
		{
			isSplit = 0;
			isCount;
		}
	}
	printf(word count is : %d\r\n, isCount);

	return 0;
}
作用域生命期
函数变量定义开始到函数结束进入函数分配空间,退出函数释放空间
块(受约束的局部变量)变量定义开始到块结束同函数
全局变量工程作用域

编译期间检查 运行期间检查

贪吃蛇小游戏

#include <stdio.h>
#include MySnake.h
#include <stdlib.h>

void main()
{
	//接收游戏的返回值
	int nRet = 0;
	nRet = StartGame();
	//游戏正常退出(撞墙或咬自己了)
	if (nRet == 2)
	{
		printf(很遗憾,游戏挑战失败!\r\n);
	}
	//游戏过关
	else if (nRet == 1)
	{
		printf(恭喜,游戏挑战成功!\r\n);
	}
	//游戏出Bug
	else if (nRet == -1)
	{
		printf(游戏维护中...\r\n);
	}

	system(pause);
}

MySnake.h

int StartGame();

#include MySnake.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>

#define ROW 8 //行
#define COL 16 //列
#define WALL 1 //墙
#define SAKE 2 //蛇
#define FOOD  //食物

//贪吃蛇数组
char g_ArySnake[ROW][COL] = { 0 };
//蛇坐标数组
char g_ArySnakeRowAndCol[((ROW - 2) * (COL - 2)  1)][2] = { 0 };
//蛇的长度
int g_nSnakeLength = 0;
//蛇行坐标
int g_nSnakeRow = 0;
//蛇列坐标
int g_nSnakeCol = 0;
//食物行坐标
int g_nFoodRow = 0;
//食物列坐标
int g_nFoodCol = 0;

//初始化墙
int InitWall()
{
	int i = 0, j = 0;

	for (i = 0; i < ROW; i)
	{
		for (j = 0; j < COL; j)
		{
			if (((i == 0) || i == (ROW - 1)) || ((j == 0) || j == (COL - 1)))
			{
				g_ArySnake[i][j] = WALL;
			}
		}
	}
	return 0;
}

//显示UI
int ShowUI()
{
	int i = 0, j = 0;
	system(cls);

	for (i = 0; i < ROW; i)
	{
		for (j = 0; j < COL; j)
		{
			if (g_ArySnake[i][j] == WALL)
			{
				printf(■);
			}
			else if (g_ArySnake[i][j] == SAKE)
			{
				printf(÷);
			}
			else if (g_ArySnake[i][j] == FOOD)
			{
				printf(⊙);
			}
			else
			{
				printf(  );
			}
		}
		printf(\r\n);
	}
	return 0;
}

//创建蛇
int CreateSnake()
{
	g_nSnakeRow = (rand() % (ROW - 2))  1;
	g_nSnakeCol = (rand() % (COL - 2))  1;

	g_ArySnake[g_nSnakeRow][g_nSnakeCol] = SAKE;

	//保存蛇头的坐标
	g_ArySnakeRowAndCol[0][0] = g_nSnakeRow;
	g_ArySnakeRowAndCol[0][1] = g_nSnakeCol;

	//蛇的长度1
	g_nSnakeLength;
	return 0;
}

//创建食物
int CreateFood()
{
	//创建食物不能产生在蛇身上
	g_nFoodRow = (rand() % (ROW - 2))  1;
	g_nFoodCol = (rand() % (COL - 2))  1;

	g_ArySnake[g_nFoodRow][g_nFoodCol] = FOOD;
	return 0;
}

//移动后的结果
int IsMove(int nSnakeRow, int nSnackCol)
{
	if (g_ArySnake[nSnakeRow][nSnackCol] == WALL)
	{
		return WALL;
	}
	else if (g_ArySnake[nSnakeRow][nSnackCol] == SAKE)
	{
		return SAKE;
	}
	else if (g_ArySnake[nSnakeRow][nSnackCol] == FOOD)
	{
		return FOOD;
	}
	return 0;
}

//清除原蛇坐标
int ClearSnake()
{
	int i = 0;
	int nSnakeRow = 0;
	int nSnakeCol = 0;
	for (i = 0; i < g_nSnakeLength; i)
	{
		nSnakeRow = g_ArySnakeRowAndCol[i][0];
		nSnakeCol = g_ArySnakeRowAndCol[i][1];
		g_ArySnake[nSnakeRow][nSnakeCol] = 0;
	}
	return 0;
}

//向上移动
int MoveUp()
{
	int nRet = 0;
	int i = 0;
	int nSnakeRow = 0;
	int nSnakeCol = 0;
	g_nSnakeRow--;
	nRet = IsMove(g_nSnakeRow, g_nSnakeCol);
	//撞墙了或者咬到自己了
	if (nRet == WALL || nRet == SAKE)
	{
		return SAKE;
	}
	else if (nRet == FOOD)
	{
		//如果蛇的长度==最长长度,就返回过关

		//清除大数组中原蛇的坐标
		if (ClearSnake() != 0)
		{
			return -1;
		}

		for (i = g_nSnakeLength; i >= 0; i--)
		{
			if (i == 0)
			{
				g_ArySnakeRowAndCol[0][0] = g_nFoodRow;
				g_ArySnakeRowAndCol[0][1] = g_nFoodCol;
				g_nSnakeRow = g_nFoodRow;
				g_nSnakeCol = g_nFoodCol;
			}
			else
			{
				g_ArySnakeRowAndCol[i][0] = g_ArySnakeRowAndCol[i - 1][0];
				g_ArySnakeRowAndCol[i][1] = g_ArySnakeRowAndCol[i - 1][1];
			}
		}

		//蛇长大一节
		g_nSnakeLength;

		//重新创建食物
		if (CreateFood() != 0)
		{
			return -1;
		}
	}
	else
	{
		//清除大数组中原蛇的坐标
		if (ClearSnake() != 0)
		{
			return -1;
		}

		//更新蛇的坐标
		for (i = g_nSnakeLength - 1; i >= 0; i--)
		{
			if (i == 0)
			{
				g_ArySnakeRowAndCol[0][0] = g_nSnakeRow;
				g_ArySnakeRowAndCol[0][1] = g_nSnakeCol;
			}
			else
			{
				g_ArySnakeRowAndCol[i][0] = g_ArySnakeRowAndCol[i - 1][0];
				g_ArySnakeRowAndCol[i][1] = g_ArySnakeRowAndCol[i - 1][1];
			}
		}
	}
	//更新大数组中蛇的坐标
	for (i = 0; i < g_nSnakeLength; i)
	{
		nSnakeRow = g_ArySnakeRowAndCol[i][0];
		nSnakeCol = g_ArySnakeRowAndCol[i][1];
		g_ArySnake[nSnakeRow][nSnakeCol] = SAKE;
	}

	if (ShowUI() != 0)
	{
		return -1;
	}
	return 0;
}

//向下移动
int MoveDwon()
{
	int nRet = 0;
	int i = 0;
	int nSnakeRow = 0;
	int nSnakeCol = 0;
	g_nSnakeRow;
	nRet = IsMove(g_nSnakeRow, g_nSnakeCol);
	//撞墙了或者咬到自己了
	if (nRet == WALL || nRet == SAKE)
	{
		return SAKE;
	}
	else if (nRet == FOOD)
	{
		//如果蛇的长度==最长长度,就返回过关

		//清除大数组中原蛇的坐标
		if (ClearSnake() != 0)
		{
			return -1;
		}

		for (i = g_nSnakeLength; i >= 0; i--)
		{
			if (i == 0)
			{
				g_ArySnakeRowAndCol[0][0] = g_nFoodRow;
				g_ArySnakeRowAndCol[0][1] = g_nFoodCol;
				g_nSnakeRow = g_nFoodRow;
				g_nSnakeCol = g_nFoodCol;
			}
			else
			{
				g_ArySnakeRowAndCol[i][0] = g_ArySnakeRowAndCol[i - 1][0];
				g_ArySnakeRowAndCol[i][1] = g_ArySnakeRowAndCol[i - 1][1];
			}
		}

		//蛇长大一节
		g_nSnakeLength;

		//重新创建食物
		if (CreateFood() != 0)
		{
			return -1;
		}
	}
	else
	{
		//清除大数组中原蛇的坐标
		if (ClearSnake() != 0)
		{
			return -1;
		}

		//更新蛇的坐标
		for (i = g_nSnakeLength - 1; i >= 0; i--)
		{
			if (i == 0)
			{
				g_ArySnakeRowAndCol[0][0] = g_nSnakeRow;
				g_ArySnakeRowAndCol[0][1] = g_nSnakeCol;
			}
			else
			{
				g_ArySnakeRowAndCol[i][0] = g_ArySnakeRowAndCol[i - 1][0];
				g_ArySnakeRowAndCol[i][1] = g_ArySnakeRowAndCol[i - 1][1];
			}
		}
	}
	//更新大数组中蛇的坐标
	for (i = g_nSnakeLength - 1; i >= 0; i--)
	{
		nSnakeRow = g_ArySnakeRowAndCol[i][0];
		nSnakeCol = g_ArySnakeRowAndCol[i][1];
		g_ArySnake[nSnakeRow][nSnakeCol] = SAKE;
	}

	if (ShowUI() != 0)
	{
		return -1;
	}
	return 0;
}

//向左移动
int MoveLeft()
{
	int nRet = 0;
	int i = 0;
	int nSnakeRow = 0;
	int nSnakeCol = 0;
	g_nSnakeCol--;
	nRet = IsMove(g_nSnakeRow, g_nSnakeCol);
	//撞墙了或者咬到自己了
	if (nRet == WALL || nRet == SAKE)
	{
		return SAKE;
	}
	else if (nRet == FOOD)
	{
		//如果蛇的长度==最长长度,就返回过关

		//清除大数组中原蛇的坐标
		if (ClearSnake() != 0)
		{
			return -1;
		}

		for (i = g_nSnakeLength; i >= 0; i--)
		{
			if (i == 0)
			{
				g_ArySnakeRowAndCol[0][0] = g_nFoodRow;
				g_ArySnakeRowAndCol[0][1] = g_nFoodCol;
				g_nSnakeRow = g_nFoodRow;
				g_nSnakeCol = g_nFoodCol;
			}
			else
			{
				g_ArySnakeRowAndCol[i][0] = g_ArySnakeRowAndCol[i - 1][0];
				g_ArySnakeRowAndCol[i][1] = g_ArySnakeRowAndCol[i - 1][1];
			}
		}

		//蛇长大一节
		g_nSnakeLength;

		//重新创建食物
		if (CreateFood() != 0)
		{
			return -1;
		}
	}
	else
	{
		//清除大数组中原蛇的坐标
		if (ClearSnake() != 0)
		{
			return -1;
		}

		//更新蛇的坐标
		for (i = g_nSnakeLength - 1; i >= 0; i--)
		{
			if (i == 0)
			{
				g_ArySnakeRowAndCol[0][0] = g_nSnakeRow;
				g_ArySnakeRowAndCol[0][1] = g_nSnakeCol;
			}
			else
			{
				g_ArySnakeRowAndCol[i][0] = g_ArySnakeRowAndCol[i - 1][0];
				g_ArySnakeRowAndCol[i][1] = g_ArySnakeRowAndCol[i - 1][1];
			}
		}
	}
	//更新大数组中蛇的坐标
	for (i = 0; i < g_nSnakeLength; i)
	{
		nSnakeRow = g_ArySnakeRowAndCol[i][0];
		nSnakeCol = g_ArySnakeRowAndCol[i][1];
		g_ArySnake[nSnakeRow][nSnakeCol] = SAKE;
	}

	if (ShowUI() != 0)
	{
		return -1;
	}
	return 0;
}

//向右移动
int MoveRight()
{
	int nRet = 0;
	int i = 0;
	int nSnakeRow = 0;
	int nSnakeCol = 0;
	g_nSnakeCol;
	nRet = IsMove(g_nSnakeRow, g_nSnakeCol);
	//撞墙了或者咬到自己了
	if (nRet == WALL || nRet == SAKE)
	{
		return SAKE;
	}
	else if (nRet == FOOD)
	{
		//如果蛇的长度==最长长度,就返回过关

		//清除大数组中原蛇的坐标
		if (ClearSnake() != 0)
		{
			return -1;
		}

		for (i = g_nSnakeLength; i >= 0; i--)
		{
			if (i == 0)
			{
				g_ArySnakeRowAndCol[0][0] = g_nFoodRow;
				g_ArySnakeRowAndCol[0][1] = g_nFoodCol;
				g_nSnakeRow = g_nFoodRow;
				g_nSnakeCol = g_nFoodCol;
			}
			else
			{
				g_ArySnakeRowAndCol[i][0] = g_ArySnakeRowAndCol[i - 1][0];
				g_ArySnakeRowAndCol[i][1] = g_ArySnakeRowAndCol[i - 1][1];
			}
		}

		//蛇长大一节
		g_nSnakeLength;

		//重新创建食物
		if (CreateFood() != 0)
		{
			return -1;
		}
	}
	else
	{
		//清除大数组中原蛇的坐标
		if (ClearSnake() != 0)
		{
			return -1;
		}

		//更新蛇的坐标
		for (i = g_nSnakeLength - 1; i >= 0; i--)
		{
			if (i == 0)
			{
				g_ArySnakeRowAndCol[0][0] = g_nSnakeRow;
				g_ArySnakeRowAndCol[0][1] = g_nSnakeCol;
			}
			else
			{
				g_ArySnakeRowAndCol[i][0] = g_ArySnakeRowAndCol[i - 1][0];
				g_ArySnakeRowAndCol[i][1] = g_ArySnakeRowAndCol[i - 1][1];
			}
		}
	}
	//更新大数组中蛇的坐标
	for (i = 0; i < g_nSnakeLength; i)
	{
		nSnakeRow = g_ArySnakeRowAndCol[i][0];
		nSnakeCol = g_ArySnakeRowAndCol[i][1];
		g_ArySnake[nSnakeRow][nSnakeCol] = SAKE;
	}

	if (ShowUI() != 0)
	{
		return -1;
	}
	return 0;
}

//游戏引擎文件
int StartGame()
{
	srand((unsigned)time(ULL));

	char szKey = 	\0	;
	int nRet = 0;

	//初始化墙
	if (InitWall() != 0)
	{
		return -1;
	}

	//创建蛇
	if (CreateSnake() != 0)
	{
		return -1;
	}
	//创建食物
	if (CreateFood() != 0)
	{
		return -1;
	}

	//显示UI
	if (ShowUI() != 0)
	{
		return -1;
	}

	//方向控制
	while (1)
	{
		szKey = _getch();
		switch (szKey)
		{
		case 	W	:
		case 	w	:
		{
			nRet = MoveUp();
			if (nRet != 0)
			{
				return nRet;
			}
			break;
		}
		case 	S	:
		case 	s	:
		{
			{
				nRet = MoveDwon();
				if (nRet != 0)
				{
					return nRet;
				}
				break;
			}
			break;
		}
		case 	A	:
		case 	a	:
		{
			{
				nRet = MoveLeft();
				if (nRet != 0)
				{
					return nRet;
				}
				break;
			}
			break;
		}
		case 	D	:
		case 	d	:
		{
			{
				nRet = MoveRight();
				if (nRet != 0)
				{
					return nRet;
				}
				break;
			}
			break;
		}
		}
	}
	return 0;
}
C 指针和地址
type* ptr = ....;
int n = .....;

prt  n = (int)ptr  sizeof(type)*n 运算结果为type * ct同类指针常量
		= (type * ct)((int)ptr  sizeof(type)*n)

数组名是数组第0个元素的指针常量
type ary[M] = ....;
ptr = ary;
ptr[n] = *(type * ct)((int)ptr  sizeof(type)*n)
int _tmain() {
	int a = 8;
	int* pa = ULL;

	pa = &a;
	*pa = 999;

	int ary[5] = { 1,2,,4,5 };
	int* pAry = ULL;
	pAry = ary;
	int n = 2;
	printf(%d\r\n, pAry[2]);
	printf(%d\r\n, ary[2]);
	printf(%d\r\n, *(pAry  n));

	_tsystem(_T(pause));
	return 0;
}
int _tmain() {
	int ary[5] = { 1,2,,4,5 };
	int* pAry = ULL;
	int n = 2;
	int* pn = ULL;
	pn = &n;
	pAry = ary;

	//这里pAry是pAry[0]的首地址,pn的地址-pAry[0]地址的差值除以数据类型的大小sizeof(type)
	printf(%d\r\n, pn - pAry);

	_tsystem(_T(pause));
	return 0;
}

//没有解释方式,只有地址
void* pv = ULL;

memcpy(目标,原,大小)

int _tmain() {
	int ary[5] = { 1,2,,4,5 };
	char aryDest[5 * sizeof(int)];
	int* pAry = ULL;
	int n = 2;
	int* pn = ULL;
	pn = &n;
	pAry = ary;

	float flt = .14f;
	printf(%f, flt);

	//没有解释方式,只有地址
	void* pv = ULL;

	/*
	块操作
	memcpy memcmp memstr memchr
	*/

	_tsystem(_T(pause));
	return 0;
}
void myswap(int* pn1, int* pn2)
{
	int nTmp = *pn1;
	*pn1 = *pn2;
	*pn2 = nTmp;
}

int _tmain() {
	int n1 = 8;
	int n2 = 10;
	printf(%d %d\r\n, n1, n2);
	myswap(&n1, &n2);
	printf(%d %d\r\n, n1, n2);

	_tsystem(_T(pause));
	return 0;
}
函数指针、数组指针
int* max(int* x, int* y)
{
	int* q;
	if (*x > *y)
	{
		q = x;
	}
	else
	{
		q = y;
	}

	return q;
}

int _tmain() {
	int a, b, * p;
	scanf(%d %d, &a, &b);
	p = max(&a, &b);
	printf(%d %d,max is%d\r\n, a, b, *p);

	_tsystem(_T(pause));
	return 0;
}

typedef 起别名,定义一个新类型,增加可读性、可移植性

函数的类型
1,参数序列(包括参数个数,类型,顺序)
2,调用约定
,返回值类型
void (_cdecl*pfnSort)(int [], int);

void SortA(int arr[], int nCount)
{
	puts(冒泡);
}

void SortB(int arr[], int nCount)
{
	puts(选择);
}

//typedef 起别名,定义一个新类型,增加可读性、可移植性
typedef void(_cdecl* PFSORT)(int[], int);



int _tmain() {
	int arr[54];
	//void(_cdecl * pfnSort)(int[], int) = ULL;
	PFSORT pfnSort = ULL;
	pfnSort = SortB;
	pfnSort(arr, 54);

	_tsystem(_T(pause));
	return 0;
}
void SortA(int arr[], int nCount)
{
	puts(冒泡);
}

void SortB(int arr[], int nCount)
{
	puts(选择);
}

//typedef 起别名,定义一个新类型,增加可读性、可移植性
typedef void(_cdecl* PFSORT)(int[], int);

void PlayCard(int arr[], int nCount, PFSORT pfnSort)
{
	//洗牌
	//发牌
	//排序
	pfnSort(arr, nCount);
	//叫地主
	//抢地主
}

int _tmain() {
	int arr[54];

	//算法和业务逻辑的分离
	PlayCard(arr, 54, SortA);
	PlayCard(arr, 54, SortB);

	_tsystem(_T(pause));
	return 0;
}
void FunA()
{
	puts(进货);
}

void FunB()
{
	puts(库存);
}

void FunC()
{
	puts(加工);
}

void FunD()
{
	puts(销售);
}

int _tmain() {
	//函数指针数组
	void(*pfnArr[])() = {
		FunA,FunB,FunC,FunD
	};

	//循环遍历出四个void
	for (int i = 0; i < sizeof(pfnArr) / sizeof(pfnArr[0]); i)
	{
		pfnArr[i]();
	}
	_tsystem(_T(pause));
	return 0;
}

*和&

void GetValue(int *nOut)
{
	*nOut=8;
}

int g_nTest = 999;

//一级使用指针
void GetPoint1(int *pnOut)
{
	pnOut=&g_nTest;
}

//二级使用指针
void GetPoint2(int **pnOut)
{
	*pnOut=&g_nTest;
}

int _tmain(int argc,char *ar[],char* envp[]) {
	
	char* arrPoint[] = {
		Hello,
		Wolrd,
		C
	};
	//数组名是第0个元素的指针常量
	//char* arrPoint是一级指针需要二级指针接收
	char** ppab = arrPoint;
	printf(%s\r\n,arrPoint[0]);
	printf(%c\r\n,arrPoint[0][0]);
	printf(%c\r\n,**arrPoint);

	
	int arr[][5] = {
		{1,2,,4,5},
		{10,20,0,40,50},
		{100,200,00,400,500}
	};

	int n = 6;
	GetValue(&n);

	int* pn = &n;
	//一级使用指针
	GetPoint1(pn);
	printf(%p\r\n,*pn);
	//二级使用指针
	GetPoint2(&pn);
	printf(%p\r\n,*pn);

	int** ppn = &pn;

	printf(%p\r\n, ppn);
	printf(%p\r\n, *ppn);
	printf(%p\r\n, **ppn);
	printf(%p\r\n, ppn[0]);
	printf(%p\r\n, ppn[0][0]);


	//数组指针类型吻合
	int(*p)[5] = arr;
	int(*pa)[][5] = &arr;

	printf(%p\r\n, p);
	printf(%p\r\n, *p);
	printf(%p\r\n, pa);
	printf(%p\r\n, *pa);
	printf(%p\r\n, **pa);

	printf(%p\r\n, p  1);
	printf(%p\r\n, *p  1);
	printf(%p\r\n, pa  1);
	printf(%p\r\n, *pa  1);
	printf(%p\r\n, **pa  1);

	//数组名是第0个元素的指针常量
	//二位数组的元素是一堆数组
	//arr[][4]的元素是int[4]
	//arr是int[4]类型的指针常量
	printf(%p\r\n, arr);

	//*arr得到int[4]一维数组
	//*arr是int类型的指针常量
	printf(%p\r\n, *arr);

	//任何类型的变量取地址得到该类型的指针
	//&arr取地址得到int[][4]类型的指针
	printf(%p\r\n, &arr);

	//arr是int[4]类型的指针常量
	//arr  1 <==> (int)arr  sizeof(int[4])*1
	printf(%p\r\n, arr);
	//*arr是int类型的指针常量
	//*arr  1 <==> (int)*arr  sizeof(int[4])*1
	printf(%p\r\n, *arr  1);

	//&arr取地址得到int[][4]类型的指针
	//*arr  1 <==> (int)&arr  sizeof(int[][4])*1
	printf(%p\r\n, &arr  1);

	//二位数组的元素是一堆数组
	//arr[0]是int[4]类型的指针常量
	//arr[0]是int类型的指针常量
	//arr  1 <==> (int)arr[0]  sizeof(int[4])*1
	printf(%p\r\n, arr[0]  1);

	//指针加整型得到同类型的指针常量
	//arr是int[4]类型的指针常量
	//arr  1 得到int[4]类型的指针常量
	//*(arr1)得到一维数组int[4]
	//数组名是第0个元素的指针常量
	//*(arr1)是int类型的指针常量
	//对int*做[1]运算得到int
	printf(%p\r\n, (*(arr  1))[1]);
	

	_tsystem(_T(pause));
	return 0;
} 
结构体
/*
设编译对齐值为 Zp
设结构体成员的地址和结构体首地址之差为offset
每个结构体成员的偏移量offset
设结构体成员类型为member type
必须满足:
offset % min (Zp,sizeof(member type)) == 0

定义结构体自身的对齐值为StructAlig
StructAlig = max(sizeof(member1 type),sizeof(member2 type)...sizeof(member type))

设整个结构体的空间长度为size
必须满足:
StructAlig = min(Zp,StructAlig)
*/
// /Zp2

struct tagDOB
{
	int nYear;
	char cMonth;
	short int wDay;
};

//保存当前对齐值
#pragma pack(push)
#pragma pack(1)
struct tagStudent
{
	struct tagDOB dob;
	char szame[5];			//5->8
	int nAge;				//4
	float fHeight;			//4
	double dblWeight;		//8
	unsigned short int wID;	//2
	char nGender;			//上面的2和1补到8
	//sizeof() == 2
};
//恢复对齐值
#pragma pack(pop)

/*
	struct tagType obj;

	 address is:
		(member type*)((int)&obj  member offset)
	 = *(member type*)( address)
*/

int _tmain(int argc, char* ar[], char* envp[]) {
	struct tagStudent stu = {
		{
			1999,
			9,
			9
		},
		Jack,
		25,
		185.0f,
		80.0,
		9527,
			m	
	};
	printf(%d\r\n, sizeof(stu));

	printf(%s\r\n, stu.szame);

	struct tagStudent* pStu = ULL;
	pStu = &stu;
	printf(%d\r\n, &*(double*)((int)pStu  8));

	//想取出偏移量,又不想取出结构体变量
#define GetOffset(s,m) (size_t)(((s*)ULL)->m)
	//printf(%d\r\n, GetOffset(tagStudent, dblWeight));

	printf(%d\r\n, &pStu->dblWeight);
	printf(%d\r\n, &pStu->dob.nYear);
	//printf(%d\r\n, pStu->);

	_tsystem(_T(pause));
	return 0;
}
结构体数组、联合体
//enum eType test = TYPE_CHAR or TYPE_FLOAT or TYPE_TEXT;
//枚举变量,变量只能赋值为对应枚举类型中的枚举常量值之一
//enum eType test = TYPE_CHAR;

struct unScore2
{
	char szText[8];
};

//变体的前身
struct tagScore
{
	//枚举类型
	enum
	{
		TYPE_CHAR,
		//枚举常量
		TYPE_FLOAT,
		TYPE_TEXT
	}nType;

	union unScore
	{
		char chLevel;
		float fPoint;
		char szText[8];
	}score;
	//union unScore tScore;
};

void SetScore(struct tagScore* pScore, char chLevel)
{
	pScore->score.chLevel = chLevel;
	pScore->nType = tagScore::TYPE_CHAR;
}

void SetScore(struct tagScore* pScore, float chPoint)
{
	pScore->score.fPoint = chPoint;
	pScore->nType = tagScore::TYPE_FLOAT;
}

void SetScore(struct tagScore* pScore, ct char* chText)
{
	strcpy(pScore->score.szText, chText);
	pScore->nType = tagScore::TYPE_TEXT;
}

void GetScore(struct tagScore* pScore)
{
	switch (pScore->nType)
	{
	case tagScore::TYPE_CHAR:
		printf(%c\r\n, pScore->score.chLevel);
		break;
	case tagScore::TYPE_FLOAT:
		printf(%f\r\n, pScore->score.fPoint);
		break;
	case tagScore::TYPE_TEXT:
		printf(%s\r\n, pScore->score.szText);
		break;
	default:
		printf(error\r\n);
	}
}

int _tmain(int argc, char* ar[], char* envp[]) {
	argc = tagScore::TYPE_TEXT;

	//改善语法的可读性
	//union联合结构体占用内存小
	/*union unScore usc1;
	printf(%d\r\n, sizeof(usc1));
	struct unScore2 usc2;
	printf(%d\r\n, sizeof(usc2));

	 = 	a	;
	*(char*)usc2.szText = 	a	;
	*
	usc1.fPoint = .14f;
	*(char*)usc2.szText = .14f;

	strcpy(usc1.szText, hello);
	strcpy((char*)usc2.szText, hello);*/

	tagScore sc1;
	SetScore(&sc1, 	A	);
	GetScore(&sc1);

	tagScore sc2;
	SetScore(&sc2, 56.9f);
	GetScore(&sc2);

	tagScore sc;
	SetScore(&sc, GOOD);
	GetScore(&sc);

	_tsystem(_T(pause));
	return 0;
}
#ifdef _DEBUG
#define malloc(n) _malloc_dbg(n, _ORMAL_BLOCK, __FILE__, __LIE__)
#endif

int _tmain(int argc, char** ar, char* envp[]) {
	int* p = (int*)malloc(4);
	*p = 999;

	char* psz = (char*)malloc(20);
	strcpy(psz, hello);

	char* psz2 = (char*)realloc(p, 1);
	*psz2 = (	a	);

	p = (int*)realloc(psz2, 8);
	p[0] = 0x6666;
	p[1] = 0x8888;

	free(p);
	free(psz2);

	_tsystem(_T(pause));
	return 0;
}
#ifdef _DEBUG
#define malloc(n) _malloc_dbg(n, _ORMAL_BLOCK, __FILE__, __LIE__)
#endif

void ErrorProc() {}

int _tmain(int argc, char **ar, char *envp[]) {

  int *pA = (int *)malloc(sizeof(int));
  if (pA == ULL) {
    ErrorProc();
    return -1;
  }
  *pA = 999;

  char *pb1;
  float *pb2;
  if (argc % 2 == 0) {
    pb1 = (char *)malloc(strlen(Hello)  sizeof(char));
    if (pb1 == ULL) {
      free(pA);
      ErrorProc();
      return -1;
    }
    strcpy(pb1, Hello);
  } else {
    pb2 = (float *)malloc(strlen(Hello)  sizeof(float));
    if (pb2 == ULL) {
      free(pA);
      ErrorProc();
      return -1;
    }
    *pb2 = .14f;
  }

  double *pC = (double *)malloc(sizeof(double));
  if (pC == ULL) {
    free(pA);
    ErrorProc();
    return -1;
  }
  *pC = 0.618;

  _tsystem(_T(pause));
  return 0;
}
C指针的使用规范、位运算
#ifdef _DEBUG
#define malloc(n) _malloc_dbg(n, _ORMAL_BLOCK, __FILE__, __LIE__)
#endif

void ErrorProc() {}

int _tmain(int argc, char **ar, char *envp[]) {

  // 多资源使用规范
  // 1.引用资源的变量在作用域开始定义,并初始化为错误值
  int *pA = ULL;
  char *pB1 = ULL;
  float *pB2 = ULL;
  double *pB = ULL;

  // 2.申请资源后,必须检查是否资源有效,无效则处理错误
  pA = (int *)malloc(sizeof(int));
  if (pA == ULL) {
    ErrorProc();
    // .处理完错误后,转移到统一退出位置
    goto EXIT_PROC;
  }

  *pA = 999;
  if (argc > ) {
    pB1 = (char *)malloc(strlen(hello)  sizeof(char));
    if (pB1 == nullptr) {
      ErrorProc();
      goto EXIT_PROC;
    }
  } else {
    pB2 = (float *)malloc(sizeof(float));
    if (pB2 == nullptr) {
      ErrorProc();
      goto EXIT_PROC;
    }
    *pB2 = .14f;
  }

  pB = (double *)malloc(sizeof(double));
  if (pB == nullptr) {
    ErrorProc();
    goto EXIT_PROC;
  }
  *pB = 0.618;

  _tsystem(_T(pause));
EXIT_PROC:
#define SAFE_FREE(p)                                                           \
  if (p) {                                                                     \
    free(p);                                                                   \
    (p) = ULL;                                                                \
  }
  SAFE_FREE(pB1);
  SAFE_FREE(pB2);
  SAFE_FREE(pB);

  // 4.释放资源前,必须检查资源是否有效,无效则不处理
  if (pA != ULL) {
    free(pA);
    // 5.释放资源后,必须将引用资源的变量重置为错误值
    // pA = ULL;
  }

  return 0;
}
位运算
A and 1 = A
A or 0 = A

A and 0 = 0
A or 1 = 1
A xor A = 0
A xor 0 = A
A xor 1 = not A

A and not A = 0
A or not A = 1
#ifdef _DEBUG
#define malloc(n) _malloc_dbg(n, _ORMAL_BLOCK, __FILE__, __LIE__)
#endif

int myabs(int n) {
	// 具体数学
	// if n >= 0, i = 0; else i = 0xffffffff = -1
	int i = n >> 1;
	// if i = 0, n = n; else i = 0xffffffff, n = ~n
	n = n ^ i;

	//if i = 0, n - i = n; else i = -1, n - i = n  1
	return n - i;
}

int _tmain(int argc, char** ar, char* envp[]) {
	int n = myabs(-5);

	_tsystem(_T(pause));
	return 0;
}
文件操作、缓存
文件访问 模式字符串意义解释如果文件 已存在,则执行操作如果文件 不存在,则执行操作
“r”打开文件进行读取从头开始阅读打不开
“w”创建用于写入的文件销毁内容新建
“a”附加追加到文件写到结束新建
“r”阅读扩展打开文件进行读/写从头开始阅读错误
“w”写扩展创建用于读/写的文件销毁内容新建
“a”追加扩展打开文件进行读/写写到结束新建
文件操作
打开/创建 fopen
文件指针 ftell(查看当前指针在哪) fseek(将当前指针移动到文件中的指定位置) feof(检查文件结束符)

关闭fclose

显示错误的原因 perror


文本方式
fputc
fputs

fgetc
fgets


二进制方式
读取数据 fread
写入数据 fwrite

写入

    /*----保存数据----*/
    //二进制打开
    FILE *fp = fopen(D:\\, wb);
    if (fp == ULL) {
        perror(fopen\r\n);
        return 0;
    }

    printf(open file ok fp:%p\r\n, fp);

    //写入数据
    size_t size = fwrite(player_name, 1, sizeof(player_name), fp);
    if (size <= 0) {
        perror(fwrite\r\n);
        return 0;
    } else {
        printf(write player_name ok size:%d\r\n, size);
    }

    //变量要取地址
    //移动文件指针
    if (fseek(fp, 16, SEEK_SET) != 0) {
        perror(fseek\r\n);
        fclose(fp);
        return 0;
    }
    size = fwrite(&player_lv, 1, sizeof(player_lv), fp);
    if (size <= 0) {
        perror(fwrite\r\n);
        return 0;
    } else {
        printf(write player_lv ok size:%d\r\n, size);
    }

    size = fwrite(&player_money, 1, sizeof(player_money), fp);
    if (size <= 0) {
        perror(fwrite\r\n);
        return 0;
    } else {
        printf(write player_money ok size:%d\r\n, size);
    }

	fclose(fp);

读取

#define _CRT_SECURE_O_WARIGS

#include <stdio.h>
#include <stdlib.h>

int main() {
	char player_name[2] = { 没穿裤子 };
	int player_lv = 99;
	float player_money = 5.5f;

	// 文件读取
	// 二进制打开
	FILE* fp = fopen(D:\\, rb);
	if (fp == ULL) {
		perror(Failed to open file);
		return 1;
	}

	size_t size = fread(player_name, 1, sizeof(player_name), fp);
	if (size != sizeof(player_name)) {
		perror(Failed to read player_name);
		fclose(fp);
		return 1;
	}
	printf(fread player_name ok size:%zu\r\n, size);
	printf(player_name: %s\r\n, player_name);

	//移动文件指针
	if (fseek(fp, 16, SEEK_SET) != 0) {
		perror(fseek\r\n);
		fclose(fp);
		return 0;
	}

	size = fread(&player_lv, 1, sizeof(player_lv), fp);
	if (size != sizeof(player_lv)) {
		perror(Failed to read player_lv);
		fclose(fp);
		return 1;
	}
	printf(fread player_lv ok size:%zu\r\n, size);
	printf(player_lv: %d\r\n, player_lv);

	size = fread(&player_money, 1, sizeof(player_money), fp);
	if (size != sizeof(player_money)) {
		perror(Failed to read player_money);
		fclose(fp);
		return 1;
	}
	printf(fread player_money ok size:%zu\r\n, size);
	printf(player_money: %.2f\r\n, player_money);

	fclose(fp);
	return 0;
}

文本方式写入

#define _CRT_SECURE_O_WARIGS

#include <stdio.h>
#include <stdlib.h>

int main() {
	char player_name[2] = { 没穿裤子 };
	int player_lv = 99;
	float player_money = 5.5f;

	//文本方式写入
	FILE* fp = fopen(D:\\, w);
	fprintf(fp, %s\r\n%d\r\n%.2f, player_name, player_lv, player_money);
	fclose(fp);
	return 0;
}
#define _CRT_SECURE_O_WARIGS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char player_name[2] = {没穿裤子};
    int player_lv = 99;
    float player_money = 5.5f;

    //字符串分割
    /*char str[] = { hello12world12test };
    char str2[200];
    strcpy(str2, str);
    char* token = strtok(str, 12);
    while (token != ULL)
    {
        printf(%s\n, token);
        token = strtok(ULL, 12);
    }
    puts(str);*/

    ////文本方式写入
    FILE *fp = fopen(D:\\, w);
    fprintf(fp,  player_name:%s\r\n player_lv:%d\r\n player_money%.2f\r\n, player_name, player_lv, player_money);
    fclose(fp);

    //文本方式读取
    char player_name2[2] = {0};
    int player_lv2 = 0;
    float player_money2 = 0;
    FILE *fp2 = fopen(D:\\, rt);
    //fscanf(fp,  player_name2:%s\r\n player_lv2:%d\r\n player_money2%.2f\r\n, player_name2, &player_lv2, &player_money2);
    char buf[260] = {0};
    while (!feof(fp2)) {
        //fgets(buf, sizeof(buf), fp2);
        //sscanf(buf, player_name:%s, player_name2);
        fscanf(fp2, player_name:%s\n, player_name2);
        fscanf(fp2, player_lv:%d\n, &player_lv2);
        fscanf(fp2, player_money:%f\n, &player_money2);
    }

    fclose(fp2);
    return 0;
}
C cin cout输入输出

C完全兼容C语言的语法

二进制 >> 汇编 >> 高级语言 C >> 面向对象(C、java、C#)


#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1108844.html

相关标签:无
上传时间: 2025-07-16 12:36:25
留言与评论(共有 5 条评论)
本站网友 二月初二龙抬头
29分钟前 发表
5 }; int* pAry = ULL; int n = 2; int* pn = ULL; pn = &n; pAry = ary; //这里pAry是pAry[0]的首地址,pn的地址-pAry[0]地址的差值除以数据类型的大小sizeof(type) printf(%d\r\n
本站网友 美瞳颜色
30分钟前 发表
\\
本站网友 宁波同仁医院
12分钟前 发表
%x\n
本站网友 电梯事件
15分钟前 发表
b); } }; int main() { MyPrint(); return 0; } #define _CRT_SECURE_O_WARIGS #include <iostream> struct stStudent { int Age; char name[0x20]; }; struct stStudent arr[]; void init() { arr[0].Age = 20; printf(%s