在C语言中字符数组、字符指针的一些特质感觉有点模糊,有些时候只知道要这样做却不知道为什么,过段时间就忘了,下次又得费时费力费钱的找答案,难受。OK,今天就好好琢磨琢磨~
先来两个基本概念:
1、声明字符数组
int a[10];
定义了一个长度为10的数组a。换句话说它定义了一个由10个对象组成的集合,这10个对象存储在相邻的内存区域中,名字分别为a[0]、a[1]、...如果pa的声明为
int *pa;
则说明它是一个指向整形对象的指针,那么赋值语句
pa = &a[0];
则可以将指针pa指向数组a的第 0 个元素,也就是说pa的值为数组元素a[0]的地址。这样,赋值语句
x = *pa;
将把数组元素a[0]中的内容复制到变量 x 中。
那么,根据指针运算的定义,pa+1将指向下一个元素,pa+i将指向pa所指向数组元素之后的第i个元素。无论数组a中元素的类型或数组长度是什么,上面结论都成立。指针加 1 意味着指向下一个对象。
所以,pa = &a[0] 也可以写成下列形式:
pa = a;
综上:&a[i] 和 a+i 的含义是相同的。相应地,如果 pa 是个指针,那么在它的表达式中也可以加下标(
是的,你没有看错)
char a[100];
char *b = NULL;
memset(a, 0, sizeof(a));
a[0] = '0';
a[1] = '1';
a[2] = '2';
b = a;
char test= b[1]; //现在test的值就是 1
但是有一点必须记住,数组名和指针之间的一个不同之处:指针是一个变量,因此,在C语言中,语句pa = a 和 pa++ 都是合法的。但是数组名不是变量,因此,类似于a = pa 和 a++形式的语句是非法的。
2、关于字符指针
char *a = "test";
这里的指针a是一个变量,它指向静态常量区的"test"的首地址,并且常规状态下“test”不可改变(当然,通过某些手段也是可以改变的)。
有了以上两点,下面继续...
1、字符数组转字符指针
有时候需要在字符数组和字符指针之间相互转换,不可避免的用到strcpy()函数,先看看它的源码:
void strcpy(char *s, char *t)
{
while ((*s++ = *t++) != '\0')
;
}
再来看个超简单的例子:
char *a = NULL;
char b[5]= {'1','2'};
a = b; //OK,这样正确
strcpy(a,b); //这样会报内存错
最开始,指针变量指向NULL,a在内存中是没有分配空间的,a = b 的时候,指针变量a指向了数组的首元素地址也就是 '1' 。但strcpy的时候,*s 是无法被赋值的,因为没有为它开辟内存空间。有人会问,开辟内存空间是吧,那行,我这样 char *a = "abc"; 现在*a 有内存空间了吧!试了发现仍然不行,因为 *a 现在是不可改变的,强行赋值当然出错。如果非要用strcpy也行,那得重新开辟内存给 a。
char *a = (char *)malloc(100); //大小自己看情况定吧
char b[5] = {'1','2'};
strcpy(a,b); //这样就没问题了
这两种方式的区别就是:
直接赋值时,改变的仅仅是指针的指向,即a指向了数组b。
使用函数strcpy时,在内存中多开辟了一块空间,也就是说现在内存中有两块内容一样空间,都为{'1','2'},一块由a指向,一块由b指向。
2、字符指针转字符数组
char *a = "123";
char b[5];
memset(b,0,sizeof(b));
b = a; //会报错
strcpy(b,a); //OK
前面说了,数组名不是变量,不能当左值,显然 b = a 会报错。
strcpy里面的两个参数传给char * 一点问题都没有,s指向b 的首地址,t指向常量区的'1'。
字符数组单个元素的值是可以改变的。这里要说一下的是字符数组初始化的问题,一般三种情况:
1、定义的时候直接用字符串赋值
char a[10]="hello";
注意:不能先定义再给它赋值
2、对数组中字符逐个赋值
char a[10]={'h','e','l','l','o'};
3、利用strcpy
参考资料:The C Programming Language