• 数组/指针/const/字符串常量的使用传值问题


     1 #include<stdio.h>
     2 #include<string.h>
     3 
     4 int main()
     5 {
     6     char a[5] = "abcd";        //常指针a指向字符串常量"abcd"的首地址,a不能被改变(不可作为左值被重新赋值)
     7     char *f = "abcd";    //f指向"abcd",上面a和这个f除了a是常指针之外没有区别,f可以作为左值
     8     
     9     const char b[10] = "safajshjf";    //常指针b指向"safajshjf"的首地址,且b指针不可更改,且数组内容不可更改
    10     const char *c = "asdfdsgd";    //c指向"asdfdsgd"的首地址,且该内存段内容不可更改
    11     char *const d = "safdsfgsdg";    //常指针d指向"safdsfgsdg"的首地址,且d本身不可更改
    12     const char* const e = "adsgfsdg";    //常指针e指向"adsgfsdg"首地址,且e本身不可更改,且该内存段内容也不可更改
    13     
    14     
    15     //上面c和d,e不同,c不是const的,c指向的内存区是const的,故c可以被重新赋值
    16     c = "fasdffds";    //c被重新赋值为"fasdffds"的首地址
    17     /*下面的三行都不行,因为数组名除了初始化时,再也不能作为左值了.而const类型的d和e也不能再作为左值.
    18     a = "afds";
    19     b = "asfdsfdgg";
    20     d = "fasdgsdg";
    21     e = "fasdfgg";
    22     */
    23     
    24     //下面的可以,a和d指向的内存段内容都可以更改
    25     strcpy(a,"sdfs");
    26     strcpy(d,"sfsdgd");
    27     /*下面的不通过,b,c,d指向的内容都不可更改
    28     strcpy(b,"sfsdgf");
    29     strcpy(c,"sfsgddg");
    30     strcpy(e,"safsgdg");
    31     */
    32     
    33     //下面把常指针赋值给非const指针,可以
    34     f = a;    
    35     f = d;
    36     /*以下赋值非法,编译出错.因b,c,e指向的内存区内容不可更改,如果进行下面的赋值,编译器不能保证别的地方不去使用f而改变内存区的内容
    37     f = b;
    38     f = c;
    39     f = e;
    40     */
    41     
    42     //下面的五个都是可以的,因为const和非const的变量都可以赋值给const类型的变量
    43     const char *g = a;
    44     g = b;
    45     g = c;
    46     g = d;
    47     g = e;
    48 
    49     return 0;
    50 }

    总结:

    const指针的用法如上例所示,分别是限制指针和指针内存区域的,有这些限制,也仅是针对当前变量的限制,如果原本的内存地址已知,后来赋值给了const*类型的指针,那么利用原来的内存地址依然是可以修改该内存区域的.

    数组名相当于*const类型的,因为数组名和*const在以后都不能再给数组名或指针赋值,而只能修改数组的内存区或指针指向的内存区.
    const* typename const类型的是指针和内存区都不可以修改的.

    特别注意上面的数组名a,这是个常指针.无论是整形数组还是字符数组,初始化的时候都是赋值初始化的,不要把字符数组的初始化理解成把一个常量字符串的指针赋值给了字符数组名.

    看看下面的反汇编

        char a[5] = "abcd";    
    00401740  mov         eax,dword ptr [___xi_z+2Ch (4020E4h)] 
    00401745  mov         dword ptr [ebp-0Ch],eax 
    00401748  mov         cl,byte ptr [___xi_z+30h (4020E8h)] 
    0040174E  mov         byte ptr [ebp-8],cl 
        const char b[8] = "safader";
    00401751  mov         edx,dword ptr [___xi_z+34h (4020ECh)] 
    00401757  mov         dword ptr [ebp-1Ch],edx 
    0040175A  mov         eax,dword ptr [___xi_z+38h (4020F0h)] 
    0040175F  mov         dword ptr [ebp-18h],eax 
        const char *c = "asdfdsgd";
    00401762  mov         dword ptr [ebp-24h],offset ___xi_z+3Ch (4020F4h) 
        char *const d = "safdsfgsdg";
    00401769  mov         dword ptr [ebp-20h],offset ___xi_z+48h (402100h) 
        const char* const e = "adsgfsdg";
    00401770  mov         dword ptr [ebp-28h],offset ___xi_z+54h (40210Ch)

    可以看出来,这是上面的程序的前五行的代码的反汇编,前两行的是赋值,汇编代码可以看出来,先把静态区中的常量字符串赋值给了eax,然后后eax转给字符数组的内存区,但是后面的三个则是直接把静态区的常量字符串的地址赋值给了指针,如果只赋值给const*指针还好,但是连*const指针也是直接赋值,结果导致了后面的strcpy(d,"sfd")的静态区内存访问错误

    本文转自:http://www.cppblog.com/FateNo13/archive/2009/07/29/91559.html

  • 相关阅读:
    call、apply、bind函数的理解以及手写。
    父div里两个子div(inline-block),为什么两个子div中间会有小缝隙,如何解决?
    手写柯里化
    arguments的理解
    New
    BFC
    useCallBack和useMemo的用法
    观察者模式和发布订阅模式
    grid布局
    Android常见输入法的包名和主类名
  • 原文地址:https://www.cnblogs.com/jason-lu/p/3627829.html
Copyright © 2020-2023  润新知