代码世界@IT·互联网代码改变世界

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

2017-05-14  本文已影响350人  CodingCode

招聘程序员面试中经常碰到分不清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. 作为指针可以操作的是指针值,那么指针内容是可以改变的,即指向另一个地址,但不能改变指针指向的内容。换句话说就是可以修改指针的值,但不能修改指针值的值。
上一篇 下一篇

猜你喜欢

热点阅读