c语言char []和char *的区别

作者: CodingCode | 来源:发表于2017-05-14 16:39 被阅读350次

    招聘程序员面试中经常碰到分不清char *和char []区别的候选者,统一认为他们不都是字符串吗?特别是近年刚毕业的学生,甚至有些还是计算机科班毕业生也解释不太清楚。

    究其原因计算机高级语言的发展已经屏蔽了计算机内部的实现模型,甚至不需要理解冯-诺伊曼计算机体系结构,也能成为一名优秀的"程序员"。


    说远了,简单的说,这两者的区别是:

    1. char []定义的是一个字符数组,注意强调是数组
    2. char * 定义的是一个字符串指针,注意强调是指针

    数组表示字符串数组,数组的每一个元素都是一个字符,修改一个数组指的是修改数组的值,即改变其中一个或者多个元素的值;而指针表示这是一个地址,其值就是一个地址,并没有字符串值的概念,修改一个指针只是把指针指向别的地址或者NULL;


    看代码例子: 全局变量
    定义全局数组变量ch1和字符串指针ch2。

    1   char ch1[] = "ABCDEFGH";
    2   char * ch2 = "abcdefgh";
    

    (在Linux x64 gcc-4.4环境下验证, 下同)
    生产的汇编码如下:

    .globl ch1
        .data
        .type   ch1, @object
        .size   ch1, 9
    ch1:
        .string "ABCDEFGH"
    .globl ch2
        .section    .rodata
    .LC0:
        .string "abcdefgh"
        .data
        .align 8
        .type   ch2, @object
        .size   ch2, 8
    ch2:
        .quad   .LC0
    

    可以看到:

    1. 变量ch1定义在data段中,大小是9字节,其值是"ABCDEFGH"字符串内容(字符串长度8加上最后一个结尾'\0')。
    2. 变量ch2定义在rodata段中,大小是8字节,其值是.LC0的地址值,注意这个大小8不是字符串中含有8个字符,而是x64下的指针地址长度;如果把字符串长度改为"abcd"4个字符,这儿大小还是8字节。

    这里就可以看出ch1的内容可以被修改,而ch2不能被修改;因为ch1的内容在数据段中,而ch2的内容在只读段中。


    在看代码例子: 函数变量
    定义函数内部数组变量ch1和字符串指针ch2。

    int foo() {
        char ch1[] = "ABCDEHGF";
        char * ch2 = "abcdefgh";
        return 0;
    }
    

    生成汇编码如下:

        .section    .rodata
    .LC0:
        .string "abcdefgh"
        .text
    .globl foo
        .type   foo, @function
    foo:
    .LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        movq    %rsp, %rbp
        .cfi_offset 6, -16
        .cfi_def_cfa_register 6
        movl    $1145258561, -32(%rbp)
        movl    $1212630597, -28(%rbp)
        movb    $0, -24(%rbp)
        movq    $.LC0, -8(%rbp)
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
    .LFE0:
        .size   foo, .-foo
    

    看处理ch1的这几条指令

    movl    $1145258561, -32(%rbp)
    movl    $1212630597, -28(%rbp)
    movb    $0, -24(%rbp)
    

    $1145258561 = 0x44434241 = 'DCBA'
    $1212630597 = 0x48474645 = 'HGFE'
    字符串"ABCDEFGH"直接按照值写进函数栈里面。

    在看处理ch2的一条指令

    movq    $.LC0, -8(%rbp)
    

    .LC0是定义在只读数据段中的字符串地址,上述指令把.LC0的地址写进函数栈中,而并没有把.LC0的内容写进函数栈中。
    可见函数foo的栈中存储了"ABCDEFGH"的内容和"abcdefgh"的地址。

    由此可见两者的取别:

    1. ch1的内容存储在函数栈中,可以被修改,函数一旦返回空间就被释放。
    2. ch2的内容保存在只读数据段中,不可被修改,其空间不会被释放。

    总结一下,回到开头提到的:

    1. ch1强调的是数组,ch2强调是指针,在各自作用域范围内有效,可操作。
    2. 作为数组可以操作的是数组值,那么数组内容是可以改变的。
    3. 作为指针可以操作的是指针值,那么指针内容是可以改变的,即指向另一个地址,但不能改变指针指向的内容。换句话说就是可以修改指针的值,但不能修改指针值的值。

    相关文章

      网友评论

        本文标题:c语言char []和char *的区别

        本文链接:https://www.haomeiwen.com/subject/scuqxxtx.html