您的位置:首页 > 编程语言

笨鸟先飞学编程系列之一理解程序中的数据2(转)

2012-06-13 17:48 239 查看
3. 指针、数组、结构体

在上一节,我们讲数据类型的时候,我们讲过字符串类型,它是一串儿char(byte)类型的序列。如果我们要定义一个连续的字符串,那就要用到了数组的概念。
在C语言中,定义一个数组变量的格式如下:
数据类型变量名[元素个数];
或者
数据类型变量名[元素个数可以留空] = {常量, [常量2|…]}; // 常量就是一个具体的数值!
比如:
char addrName[] = “52pojie.cn\0”; // 定义一个字符数组,并初始化。
int ntemp[5] = {0,2,4,6,8}; // 定义一个有个元素的整型数组,并初始化。
float fTemp[10]; // 声明一个有个元素的浮点型数组,没初始化。
比如上例中第一个字符数组,addrName[0]中的内容就是‘5’,addrName[1]中的内容就是‘2’,addrName[6]中的内容就是’e’了,依次类推!
这个字符串它在内存中的样子大概如下:



也就是说,我们的addrName[0]就是内存中的地址0x00438AC0,addrName[1]就是内存中的地址0x00438AC1;
这里需要说明的一点,就是,所有的变量名,函数名,对象名等等,都是它所代表的内存地址的首地址!也就是说: addrName == addrName[0] == 0x00438AC0;
好了,由于我还没有能力写基础教程,所以,这里对C变量相关的基础就说到这里,再次回到我们的主题:变量就是地址!
如果我们有一个需求,就是将我们上面声明的这个字符串变量输出出来,那我们的程序需要怎么写呢?
// test.cpp : Defines the entry point for the application.
//
#include "stdio.h"
#include <windows.h>
char addrName[] = "52pojie.cn\0";
char *szTitle = "Null\0";
// Foward declarations of functions included in this code module:
int main()
{
MessageBoxA(NULL, addrName , szTitle, MB_OK);
return 0;
}
像我们搞破解搞逆向的,一定不会对这个MessageBoxA函数陌生吧~~,它反汇编的样子大概是:



相关内存的帖图:



大家自己根据我提供的截图,算一下上面push后面的地址的内容想必就应该很清楚的发现,我们在程序中使用的变量就是直接使用的地址,比如:
00401008 |. 68 30604000 push 00406030 ; |Text = "52pojie.cn"
这里的00406030 就是字符串52pojie.cn的首个地址,那EAX中的是什么内容啊?应该也是地址吧~~~?
我们看一下0x0040603C中的内容,也就是EAX的内容:0x00406040,再看一下0x00406040中的内容,很容易的发现,原来是“Null”,奇特吧~~~
这个就是我们C语言中说到的指针的概念,很多没有好好学C语言的朋友可能都迷糊指针的概念,我们通过这个例子就应该可以很容易的明白,指针就是存放变量的地址的变量 或者直接说 指针就是地址的地址!
指针在C语言中的表示就是*,在汇编语言中的表示就是[],至于为什么要有指针,指针到底有什么作用,在写程序的过程中,指针的功能到底应该怎么使用,我会在以后的指针的课题中详细介绍!

下面讲一下结构体。
如果说,数组是一串连续的相同类型数据的序列,那结构体就可以理解为一串连续的不同类型的数据的序列。
在C语言中,定义结构体的语法格式是:
struct 结构体名称
{
基础类型1 成员变量名1;
基础类型2 成员变量名2;
……
}结构体变量名01, 结构体变量名02…;

在实际使用的过程中,我们一般用typedef关键字来定义结构体类型(自定义数据类型),然后使用我们自己定义的数据类型来声明结构体变量,这样使用起来更加条例,比如:
typedef struct _GAME_OBJECT_INFO
{
DWORD UnKnown1[15]; // 未知 offset 0
float fX; // X坐标 offset 0x3C
float fZ; // Z坐标 offset 0x40
float fY; // Y坐标 offset 0x44
DWORD UnKnown2[55]; // 未知 offset 0x48
DWORD dwSID; // 怪物ID offset 0x124
DWORD UnKnown3[78]; // 未知 offset 0x128
wchar_t *wszName; // 名字 offset 0x260
}GAME_OBJECT_INFO, *PGAME_OBJECT_INFO;
这样我们就很容易的定义了两个游戏对象信息的数据类型,在使用这个类型来声明这个结构体的变量就很合规矩了。如下:
GAME_OBJECT_INFO Goi; // 声明一个结构体变量
PGAME_OBJECT_INFO pGOI = NULL; // 声明一个结构体指针
RtlZeroMemory(pGOI, sizeof(GAME_OBJECT_INFO)); // 给结构体指针初始化。

当然,在现在版本的C++中,它支持在结构体中使用函数(允许结构体中有成员函数),也就是说,结构体可以当做类来直接使用,深入的研究结构体可以弄明白现在C++中一些类的基础概念,为了节省篇幅,我就不再这里牢骚了。
四、 结束语
本文讲述了很多的东西,很杂,而且几乎都不是很深入,我的表述能力有限,我自认为是用我认为最普通的方式,讲述这些东西了,肯定还有很多的同学不明白我讲了写什么,我也深知我没有能力讲述更基础的教程了,就写到这里,希望大家能先看基础的一些C/C++教程,然后再参考本文,以加深理解,也避免我文中错误的理解误导大家。

本文中肯定存在很多的错误,希望大家能多多指教。
转自:http://www.cppblog.com/besterChen/archive/2009/03/23/77613.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据 编程 结构体
相关文章推荐