c语言char []和char *的区别
2017-05-14 本文已影响350人
CodingCode
招聘程序员面试中经常碰到分不清char *和char []区别的候选者,统一认为他们不都是字符串吗?特别是近年刚毕业的学生,甚至有些还是计算机科班毕业生也解释不太清楚。
究其原因计算机高级语言的发展已经屏蔽了计算机内部的实现模型,甚至不需要理解冯-诺伊曼计算机体系结构,也能成为一名优秀的"程序员"。
说远了,简单的说,这两者的区别是:
- char []定义的是一个字符数组,注意强调是数组。
- 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
可以看到:
- 变量ch1定义在data段中,大小是9字节,其值是"ABCDEFGH"字符串内容(字符串长度8加上最后一个结尾'\0')。
- 变量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"的地址。
由此可见两者的取别:
- ch1的内容存储在函数栈中,可以被修改,函数一旦返回空间就被释放。
- ch2的内容保存在只读数据段中,不可被修改,其空间不会被释放。
总结一下,回到开头提到的:
- ch1强调的是数组,ch2强调是指针,在各自作用域范围内有效,可操作。
- 作为数组可以操作的是数组值,那么数组内容是可以改变的。
- 作为指针可以操作的是指针值,那么指针内容是可以改变的,即指向另一个地址,但不能改变指针指向的内容。换句话说就是可以修改指针的值,但不能修改指针值的值。