• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 指針變量初始化----內存中怎么做的?

    發表于:2007-05-25來源:作者:點擊數: 標簽:----初始化指針怎么內存
    摘自: www.chinaunix.net R.Ihskaka 新手上路 因為學校的機器沒有 linux ,所以我用了xp+vc6,文件名為test.c 代碼是在Release模式下de bug 的,因為DEBUG模式會對環境有依賴. 這個是源碼: #includestdio.h #define SU CC ESS 1 #define FAILURE 0 void main()

    摘自:www.chinaunix.net

    R.Ihskaka  
    新手上路
    因為學校的機器沒有linux,所以我用了xp+vc6,文件名為test.c

    代碼是在Release模式下debug的,因為DEBUG模式會對環境有依賴.

    這個是源碼:

    #include<stdio.h>
    #define SUCCESS 1
    #define FAILURE 0
    void main()
    {
    char *lpTest = "ABCD";
    printf("The String is: %s n ",lpTest);
    *(lpTest+1) = 'X';
    printf("The String is: %s n ",lpTest);
    }

    發表于: 2005-01-15 11:35 

    在下新人,也想參與下討論,哪里說的不對,請各位包涵并指出 icon_smile.gif

    因為學校的機器沒有linux,所以我用了xp+vc6,文件名為test.c

    代碼是在Release模式下debug的,因為DEBUG模式會對環境有依賴.

    這個是源碼:

    #include<stdio.h>
    #define SUCCESS 1
    #define FAILURE 0
    void main()
    {
    char *lpTest = "ABCD";
    printf("The String is: %s n ",lpTest);
    *(lpTest+1) = 'X';
    printf("The String is: %s n ",lpTest);
    }


    這是由vC6的Debug的匯編代碼,其中帶///////// 的為c代碼,下面的是對應的匯編代碼:

    ///void main() //這行自己加的,就從這里開始了
    {
    00401000 55 push ebp
    00401001 8B EC mov ebp,esp
    00401003 51 push ecx
    6: char *lpTest = "ABCD"; ////////////////
    00401004 C7 45 FC 30 70 40 00 mov dword ptr [lpTest],offset ___xt_z+8 (00407030)
    7: printf("The String is: %s n ",lpTest);////////////////
    0040100B 8B 45 FC mov eax,dword ptr [lpTest]
    0040100E 50 push eax
    0040100F 68 38 70 40 00 push offset ___xt_z+10h (00407038)
    00401014 E8 1F 00 00 00 call _printf (00401038)
    00401019 83 C4 08 add esp,8
    8: *(lpTest+1) = 'X';////////////////
    0040101C 8B 4D FC mov ecx,dword ptr [lpTest]
    0040101F C6 41 01 58 mov byte ptr [ecx+1],58h
    9: printf("The String is: %s n ",lpTest);////////////////
    00401023 8B 55 FC mov edx,dword ptr [lpTest]
    00401026 52 push edx
    00401027 68 50 70 40 00 push offset ___xt_z+28h (00407050)
    0040102C E8 07 00 00 00 call _printf (00401038)
    00401031 83 C4 08 add esp,8
    10: }
    00401034 8B E5 mov esp,ebp
    00401036 5D pop ebp
    00401037 C3 ret

    程序運行時,其實lpTest很明顯是存放在堆棧里的(0x012ff7c) 從匯編上看到,lpTest開始時,push ecx,并將lpTest指向ecx寄存器的內容為地址的區域,在
    mov dword ptr [lpTest],offset ___xt_z+8 (00407030)
    后,lpTest才真正指向了定義的"ABCD".而這個"ABCD"的存放地址是0x00407030 . 可見賦值號右邊的常量其實是開辟在一個單獨的區域里,而且似乎所有的字符常量都是這樣.在printf()里的"The String is: %s"也是存放在0x00407030之后的地址上,調用時push的.

    這樣,對于lpTest本身來說,它其實就是變量而已,可以改變它指向的內容是很正常的.(不正常C語言早浮云了^_^ ) 而對于賦值號右邊的字符串常量,它們是單獨存放在一個區域的,指針依靠地址來使用他們.

    其實只要將 char *lpTest = "ABCD" 改為: const char *lpTest = "ABCD"
    就不可以再改變它的數值了.而加上const后的匯編代碼,和沒有加上時其實是一樣的,"ABCD"仍然放在0x00407030. 只是如果你加了const,還試圖改變lpTest的數值,那么編譯時就會失敗,這個看起來是由編譯器保證的.這個我不能肯定,編譯原理還沒學,說不清楚 (>_<)

    那么如果是: const char Arry[]="WXYZ" 呢?

    00401000 55 push ebp
    00401001 8B EC mov ebp,esp
    00401003 83 EC 0C sub esp,0Ch
    8: const char Arry[]="WXYZ"; ////////////////
    00401006 A1 30 70 40 00 mov eax,[___xt_z+8 (00407030)]
    0040100B 89 45 F8 mov dword ptr [Arry],eax
    0040100E 8A 0D 34 70 40 00 mov cl,byte ptr [___xt_z+0Ch (00407034)]
    00401014 88 4D FC mov byte ptr [ebp-4],cl
    .........................

    其實還是一樣,字符串常量都是開辟在0x00407030的,但是用了const,就會把這個地址的內容,拷貝到堆棧中去,然后利用
    mov cl,byte ptr [___xt_z+0Ch (00407034)]
    mov byte ptr [ebp-4],cl
    來調整一下,使Arry的地址精確指向堆棧中的4個字節,這樣就是數組字符串常量了

    那再改改,寫成這樣:
    const char Arry="WXYZ"; //bt寫法,請勿模仿! ^^
    嘿嘿~~編譯有個警告,運行,就報錯拉~~

    00401000 55 push ebp
    00401001 8B EC mov ebp,esp
    00401003 83 EC 08 sub esp,8
    8: const char Arry="WXYZ";/////////////////////////
    00401006 B8 30 70 40 00 mov eax,offset ___xt_z+8 (00407030)
    0040100B 88 45 FC mov byte ptr [Arry],al
    ............................

    這樣寫語法是沒有錯誤,但是再執行時,eax中存放的并不是來自0x00407030區域的內容,而是它的地址:
    mov eax,offset ___xt_z+8 (00407030)
    這樣再調用printf時,就會出錯了,因為 mov byte ptr [Arry],al 會把
    0x00000030這樣一個數值賦值給Arry,那么printf使用時,會引用這個地址做字符串首地址,那么自然就是非法了.這么低的地址能給你隨便訪問么~~
    這樣的話,你只要改下 printf語句,寫成:printf("The String is: %d n ",Arry);或者是printf("The String is: %c n ",Arry); 就可以正常運行了.因為這時候Arry的內容不再做地址,而是做了數值,這樣當然沒有問題了 icon_smile.gif

    呼~呼,高手看了勿笑,菜鳥的一點小見解,有錯之處,請斑竹和高手們多多包含

    _________________

    恩,請教下aero斑竹,如果是
    char *lpTest = "ABCD" 的話,
    應該怎么設置編譯器參數,使得lpTest指向的內容不可修改呢?

    常量,今天上來看到這么多常量的討論......
    其實不管是常量還是變量,必然有地址.包括printf("xxxxx") 這個"xxxxx"照樣有地址,vc6下應該在0x00407030開始,往后的某個位置上, (取決于你程序中定義的位置了).只是你定義方式的不同,編譯器處理起來就會不同,具體看我發的上個回復.

    編譯器除了語法檢查外,看到的全是地址和數據.const是靠編譯器的語法保證的.就象你在C++里取類私有函數的地址,就很困難,是因為編譯器在C++編譯方式下就不允許,而不是別的什么.

    但是就算是const 修飾,也有辦法,直接用指針取到地址就行,編譯器會給你個類型匹配的警告,不過運行會正常. 用匯編也可以:

    #include<stdio.h>
    #define SUCCESS 1
    #define FAILURE 0
    void main()
    {
    const char Arry[]="WXYZ";

    // const char *lpTest = "ABCD";

    // printf("The String is: %s n ",lpTest);
    //*(lpTest+1) = 'X';
    printf("The String is: %s n ",Arry);
    __asm
    {
    mov [Arry],31h
    mov [Arry+1],31h
    mov [Arry+2],31h
    mov [Arry+3],31h
    }

    printf("The String is: %s n ",Arry);
    }

    //用int型也是一樣

    #include<stdio.h>
    #define SUCCESS 1
    #define FAILURE 0
    void main()
    {
    // const char Arry[]="WXYZ";
    const int Arry = 1;
    // const char *lpTest = "ABCD";

    // printf("The String is: %s n ",lpTest);
    //*(lpTest+1) = 'X';
    printf("The Number is: %d n ",Arry);
    __asm
    {
    mov [Arry],99
    // mov [Arry+1],31h
    // mov [Arry+2],31h
    // mov [Arry+3],31h
    }

    printf("The Number is: %d n ",Arry);
    }


    運行了看結果吧 xp+vc6通過.

    原文轉自:http://www.kjueaiud.com

    評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>