寫一個函數fn(),功能是傳一個參數是字串,尋找裡面有沒有相同的字元,有的話返回1,否則0.
兩種方法,一是效率最高的,二是最節省記憶體的.
int fn0(const char *str)
{
char num[256] = {0};
unsigned char *pos = (unsigned char *)str;
while (*pos != 0 && num[*pos] == 0) {
num[*pos++] = 1;
}
return *pos == 0 ? 0 : 1;
}
int fn1(const char *str)
{
const char *p1, *p2;
if (*str == 0)
return 0;
for (p1 = str; *p1 != 0; p1++) {
for (p2 = p1 + 1; *p2 != 0; p2++) {
if (*p1 == *p2)
return 1;
}
}
return 0;
}
/****************************************************************/
#include <stdio.h>
int main(void)
{
const short int c1 = (short)49920;
const int c2 = 1073742008;
int (*pf)() = (int (*)())&c2;
printf("%c%c/n", *(char*)pf()-19, *((char*)pf()+1)-49);
return 0;
}
運行這個程式,螢幕上會出現一個:)
很多人不懂其中的道理,在這裡我給大家分析下代碼。
先看這兩句:
const short int c1 = (short)49920;
const int c2 = 1073742008;
定義了兩個局部變數,數值轉換成16進位為:
const short int c1 = (short)0xC300;
const int c2 = 0x400000B8;
其中變數c1的地址為:0x0012FF7C,佔兩個位元組,c2的地址為:0x0012FF78,佔四個位元組。這兩個變數佔據了連續的空間。
變數賦值後,從0x0012FF78開始的記憶體單中繼存放區的位元組碼為:B8 00 00 40 00 C3 。對應的彙編碼是:
mov eax,400000h
ret
接下來的這句:
int (*pf)() = (int (*)())&c2;
分析如下:
定義了一個函數指標,參數為NULL,傳回值為int類型。 這個函數指標,指向上面的彙編碼。這樣,後面執行pf(),就執行了這段
彙編碼。
繼續分析下面這句代碼:
printf("%c%c/n", *(char*)pf()-19, *((char*)pf()+1)-49);
先看*(char*)pf()-19這個運算式, 執行了pf指向的彙編代碼,從彙編代碼看,
這個函數調用後的傳回值是0x400000,pf()前面的char *是把函數的傳回值轉換成一個
char*型指標,這個指標指向0x400000,前面再加個*號,表示取0x400000地址的內容,
由於是char *型指標,因此從這個地址取一個位元組。
*(char*)pf()-19 表示的是從0x400000取出的位元組內容再減去19。
接下來:*((char*)pf()+1)-49代表的意思是從0x400000 + 1的地址取出一個位元組內容在減去49。
熟悉PE檔案結構的朋友一定知道,對於exe檔案0x400000是記憶體載入的基地址。
也就是說,0x400000 位元組的內容對應的是0x4D,0x400001 位元組的內容對應的是0x5A.
這是我們常說的PE檔案起始的兩個位元組,"MZ"
這樣,運算式*(char*)pf()-19的結果是0x3A ,運算式*((char*)pf()+1)-49的結果是0x29
察看ASCII碼錶,輸出就是我們看到的樣子。
總結:
別看一個這麼小的程式,但是其中涉及的知識面比較廣。
VC++6.0SP6 Release模式下錯誤,在Project Settings--->C/C++--->Project Options中去除最佳化選項/O2即可。
/********************************************************************************/