C笔记-字符指针与字符数组的区别

作者:聂勇 欢迎转载,请保留作者信息并说明文章来源!

在学习C语言指针的过程中,碰到了不少问题,字符指针和字符数组就是其中的一个。其实就是对C语言的一些基础概念没有理解透。

环境 | enviroment

  • Ubuntu-10.10
  • Redhat-5.7

字符指针与字符数组 | character pointer and character array

1、首先来看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
* === FUNCTION ======================================================================
* Name: main
* Description:
* =====================================================================================
*/
int main ( int argc, char *argv[] )
{
char *pName = "abcdefghijklmnopqrstuvwxyz";
printf ( "pName:%s\n", pName );
printf ( "lenght of opName:%d\n", strlen(pName) );
strcpy ( pName, "123456" );
printf ( "pName:%s\n", pName );
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */

2、代码顺利通过编译,但在运行时却报错:

1
./string

pName:abcdefghijklmnopqrstuvwxyz
lenght of opName:26
段错误

3、现在我们分析其原因:

  • 用gdb调试代码,发现是在执行 strcpy ( pName, “123456” ); 这行代码的时候发生了段错误。
  • 查看方法strcpy的定义及说明:char strcpy(char dest, const char src); ,第一个参数是复制的目的地址(指针类型),第二个参数是复制源地址(指针类型)。首先src没有超过dest的空间,那么问题就出在对dest的写操作上。
  • dest 必须是可写,但 char pName = “abcdefghijklmnopqrstuvwxyz”; 定义的是一个字符串常量,其内容存放在静态数据区,不可修改

4、修正代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
* === FUNCTION ======================================================================
* Name: main
* Description:
* =====================================================================================
*/
int main ( int argc, char *argv[] )
{
char pName[] = "abcdefghijklmnopqrstuvwxyz";
printf ( "pName:%s\n", pName );
printf ( "lenght of opName:%d\n", strlen(pName) );
strcpy ( pName, "123456" );
printf ( "pName:%s\n", pName );
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */

说明:将 *pName 改成 pName[],修改后其内容存放在栈内,可修改。

重新编译后,运行结果如下:

pName:abcdefghijklmnopqrstuvwxyz
lenght of opName:26
pName:123456

附录:strcpy 的注意事项

strcpy 方法在复制的时候,如果 src 的长度小于 dest 的长度,复制后并不会清空 dest 的剩余空间。通过看运行时的内存数据可知道:
1、执行 strcpy 前
dest 的内存数据:
0xbfffeff1: 97 ‘a’ 98 ‘b’ 99 ‘c’ 100 ‘d’ 101 ‘e’ 102 ‘f’ 103 ‘g’ 104 ‘h’
0xbfffeff9: 105 ‘i’ 106 ‘j’ 107 ‘k’ 108 ‘l’ 109 ‘m’ 110 ‘n’ 111 ‘o’ 112 ‘p’
0xbffff001: 113 ‘q’ 114 ‘r’ 115 ‘s’ 116 ‘t’ 117 ‘u’ 118 ‘v’ 119 ‘w’ 120 ‘x’
0xbffff009: 121 ‘y’ 122 ‘z’ 0 ‘\000’

2、执行 strcpy 后 *dest 的内存数据:
0xbfffeff1: 49 '1' 50 '2' 51 '3' 52 '4' 53 '5' 54 '6' 0 '\000' 104 ‘h’
0xbfffeff9: 105 ‘i’ 106 ‘j’ 107 ‘k’ 108 ‘l’ 109 ‘m’ 110 ‘n’ 111 ‘o’ 112 ‘p’
0xbffff001: 113 ‘q’ 114 ‘r’ 115 ‘s’ 116 ‘t’ 117 ‘u’ 118 ‘v’ 119 ‘w’ 120 ‘x’
0xbffff009: 121 ‘y’ 122 ‘z’ 0 ‘\000’

既然原来的内容都在,那为什么读取出来的是”123456”呢?因为C语言中字符串是以NUL(\000)结尾,所以当读到NUL(\000)时就认为字符串已经结束,后面的内容就被忽略了。