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

// 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';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kagula086

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值