3.         指针、数组、结构体

在上一节,我们讲数据类型的时候,我们讲过字符串类型,它是一串儿charbyte)类型的序列。如果我们要定义一个连续的字符串,那就要用到了数组的概念。

C语言中,定义一个数组变量的格式如下:

数据类型   变量名[元素个数];  

或者   

数据类型   变量名[元素个数可以留空] = {常量, [常量2|…]} //  常量就是一个具体的数值!

比如: 

char     addrName[]    = 52pojie.cn\0;         // 定义一个字符数组,并初始化。

int      ntemp[5] = {0,2,4,6,8};              // 定义一个有个元素的整型数组,并初始化。

float    fTemp[10];                                // 声明一个有个元素的浮点型数组,没初始化。

比如上例中第一个字符数组,addrName[0]中的内容就是‘5addrName[1]中的内容就是‘2addrName[6]中的内容就是’e’了,依次类推!

    这个字符串它在内存中的样子大概如下:
      

也就是说,我们的addrName[0]就是内存中的地址0x00438AC0addrName[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 , szTitleMB_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;

基础类型成员变量名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