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

C语言指针与结构体,示例代码

2015-06-11 13:21 531 查看
// testMemoryTrace.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <assert.h>

#include <iostream>
using namespace std;

/*
标题:C语言指针与结构体,示例代码
Title:C language pointer and struct.
Date:2015-6-11
Author:Kagula
Environment:VS2013Update4,IDA Pro 6.6
Destination:测试IDA Pro对内存块的trace。
Reference:
[1]使用Visual Studio2005进行C和汇编的混合编程 http://blog.csdn.net/crazii/article/details/2949374 */

//注意:这里的byte是四字节sizeof(unsigned char*)=4,不是单字节sizeof(unsigned char)=1。
//      所以指向byte的指针,移动单位为四字节。
typedef unsigned char* byte;

struct structA{
byte *pA;
byte *pB;
} a;

/*
Change1、Change2、Change3在功能上是等价的。
都是为了修改结构体第二个元素对象所指向的内存块的值。
采用不同的语法,主要是为了演示指针的结构的关系。
*/
void Change1(byte* pA);
void Change2(byte* pA);
void Change3(byte* pA);

/*
Change2_1、Change2_2在功能上是等价的。
都是为了修改结构体第二个元素对象所指向的内存块第二个数据单元的值。
采用不同的语法,主要是为了演示指针的使用。
*/
void Change2_1(byte* pA);
void Change2_2(byte* pA);
void Change2_3(byte* pA);

byte buf[22];//测试这块内存是否能被IDA Pro trace。
int _tmain(int argc, _TCHAR* argv[])
{
cout << "测试IDAtrace内存区域,输入任意键继续。。。" << endl;
cin.get();

//初始化样本
//“unsigned char*”是四字节,所以这里清空了4*22=88个字节。
//所以buf上分配的也是4*22节字节。
memset(buf, 0, sizeof(buf));

a.pA = nullptr;
a.pB = buf;

{
/*
Change1 function is modify the second pointer object reference data of the struct.
Change1、Change2 and Change3 function 's effect is equality.
Here is for illustrate different semantic C language statement.
*/
Change1((byte*)(&a));
cout << (char*)a.pB << endl;

Change2((byte*)(&a));
cout << (char*)a.pB << endl;

Change3((byte*)(&a));
cout << (char*)a.pB << endl;
}
cout << "=====================================================" << endl;
{
Change2_1((byte*)(&a));
cout << (char*)a.pB << endl;

Change2_2((byte*)(&a));
cout << (char*)a.pB << endl;

Change2_3((byte*)(&a));
cout << (char*)a.pB << endl;
}

//after input any key, the program will return!
cin.get();

return 0;
}

//修改字符串的值
void Change1(byte* pA)
{
char array1[] = "apple";
int  len = sizeof(array1);

structA *p1 = (structA *)pA;

memcpy(p1->pB, array1, len);
}

void Change2(byte* pA)
{
char array1[] = "banana";
int  len = sizeof(array1);

/*
pA是指针对象,在32位下指针对象是四字节单位,所以(pA+1)实际上是偏移四个对象
即指向下一个byte元素。
*/
byte* ppB = (pA + 1);

//ppB指向的也是内存(地址),所以可以像下面的形式那样调用。
memcpy(*ppB, array1, len);
}

void Change3(byte* pA)
{
char array1[] = "pear";
int  len = sizeof(array1);

/*
pA加1是地址,pA加1指向的也是地址
所以可以看成是指针的指针。
*/
byte** pB = (byte**)(pA + 1);

memcpy(*pB, array1, len);
}

//功能:修改字符串的第二个字符的值为'Y'。
void Change2_1(byte* pA)
{
char array1[] = "apple";
int  len = sizeof(array1);

structA *p1 = (structA *)pA;

/*
编译器把“byte*”作为四字节为单位的数组,
所以索引[1]其实是加4,
所以实际修改的是字符串第五个字节的值
*/
//p1->pB[1] = (byte)'Y';

/*
这里把“byte*”转为“char*”
编译器就会从“4字节单位”改为“单字节单位”增量。
这里正确的修改了字符串第二个字节的值。
*/
char *pB = (char*)p1->pB;
pB[1] = 'Y';
}

//功能:修改字符串的第二个字符的值为'X'。
void Change2_2(byte* pA)
{
byte* ppB = (pA + 1);
byte* pB = (byte*)(*ppB);

//pB字符串的第五个字节(地址+4)的值为'X'。
//因为pB是指针对象,32位系统下,指针对象的大小为4。
//pB[1] = byte('X');
//*(pB + 1) = byte('X');//同上面等价

//如果不想转成char*来处理,那就只能用下面的ASM代码了。
//设置pB字符的第二个字符的值为'X'。
__asm  inc dword ptr[pB]     ; pB是局部存储空间,所以是pB指向的地址+1.
__asm  mov eax, dword ptr[pB]; 取出pB指向的地址,因为地址是四字节长度,所以得用“dword ptr”修饰。
__asm  mov byte ptr[eax], 43h; 我们把pB当作指向单字节数据的指针,所以,这里用“byte ptr”修饰。
}

void Change2_3(byte* pA)
{
byte** pB = (byte**)(pA + 1);

//因为pB是指针对象,32位系统下,byte指针对象的大小为4
//所以这里改变的是第5个字节的值。
//(*pB)[1] = byte('Z');

//设置第二个字符的值为'e'
//__asm  mov ecx, dword ptr[pB]    ; pB是局部存储空间,所以得取出pB指向的地址。
//__asm  mov edx, dword ptr[ecx]   ; 取地址的地址。
//__asm  mov byte ptr[edx + 1], 'e'; 地址偏移一位,然后设置地址所指向的单字节内存块的值。

//这段C代码同上面的ASM代码等价
//“char*”是单字节为单位增量,不同于“byte*”四字节为单位增量。
//所以正确修改了字符串第二个元素的值。
char *pB_char = (char*)*pB;
pB_char[1] = 'e';
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: