大家在用纯C来进行有关字符串操作时并不像C++那样方便,因为C++里面封装了CString类以及很多很全面的与之相关的处理函数,而C里面很多地方还没有这么人性化。下面讨论一些或许大家会碰到的一些问题:
1.选用字符指针还是字符数组来存储字符串的问题。
2.两种存储方式分别以何种方式来管理输入字符串的问题。
3.两种方式的输出问题。
首先来说一下指针和数组的内存分配在内存中的存储方式,这对于理解数组和指针很重要。假如程序中有这样的声明:char *name和char name1[20],那么他们在编译时内存分配是这样的:
对于指针方式而言,它给name分配内存单元,它是一个四字节的单元(VC)用来存储字符型地址,即指针变量名name代表存储字符型地址的确定单元,sizeof(name)=4。但其存储的地址并未初始化,所以这时的指针name指向的位置是不可预料的是危险的(不过就变量本身name的地址,即这个4字节单元的地址&name是确定的)。这就好比将一个旋转的硬币放于一个铁盒中再将这个铁盒放于你书桌的右边抽屉里,这时铁盒就是指针变量name,你知道它确切的位置——在右边抽屉里;而铁盒中的旋转硬币就是这个name里的地址,我们无法预料他最终朝上的一面是什么。所以这时任何对于更改指针指向内存单元内容的操作都是危险的,很多时候会报错:某某内存不能为read!解决办法:法1. 加上语句,“name=name1;(或name=&name[0];)”;法2. 加上分配空间操作,“name=(char *)malloc(20*sizeof(char));”。
对于数组方式而言,编译器给它分配的内存大小要由数据类型和数组长度而定。这里的类型和长度分别为:char和20,所以最终分配的内存空间为1*20=20字节。此时数组名name代表的是整个数据结构(即数组)所以,sizeof(name1)=20;这时可能有人会有疑问,数组名不就是同指针一样吗?这就涉及到了数组名得本质问题,不明白的可以看一下我转载的文章《C/C++数组名与指针区别深入探索》(http://tech.163.com/05/0823/11/1RR94CAS00091589.html和http://topic.csdn.net/t/200
60104/09/4496963.html的18楼)。
现在我们可以来讨论第一个问题了:
由前面的内存分配介绍我们知道,用字符数组作为存储方式是有长度界限的,对于像人名这样的字符串采用这种凡是比较方便,同时数组的地址值是稳定的,程序运行时是不允许改变的。当name1[0]跳到name1[5]后能随时找到其他之前数据的地址,而指针就不一定了,因为指针的值是随时可以被改变的,所以一旦name值被改变除非是之前的地址有记录否则很难找到。用字符指针作为字符串的存储方式可以随时调整空间大小和指向的对象,对于像语言这种长度浮动较大或作为中转临时时常接受不同的字符串可采用此方式。
第二个问题:
对于两种存储方式都是直接将名传递给输入函数的,比如name和name1,因为输入函数像scanf和gets都是将输入内容写入地址所指向的空间。下面讨论一下用scanf和gets的区别(输入格式都为%s):
首先相同的地方是,这两种函数都接受字符的连续输入并自动将最后的换行符(换行操作产生)舍弃,并自动在字符串末尾加上'/0'。这看似没其他问题了,但实际中我们的字符串有的中间含有空格、有的没有,而scanf和gets对这两种情况的处理方式不一样也就决定了他们俩擅长的地方不同。scanf()会将空格也作为当前输入字符串的结束标志(注意,再输入任何字符之前的空格和换行符不会对输入造成影响),所以一旦有这样的输入:“black angel”,那么实际接受的字符串仅为“black”,剩下的部分等待下一次接收输入的操作。不过这种情况并不是说就一无是处的,当需要循环(连续)给很多不同的字符数组或字符指针输入字符串时,可以用空格作为分隔符一次将所有的都输入,对于打字来说就方便多了。另外一个scanf()函数可以针对多个字符串输入:scanf("%s%s%s",name,name2,name3),输入时中间用空格或换行隔开。对于gets()函数,则将空格符作为一般的字符来接收,好处就是它是需要很多空格符的字符串的福音。一个gets不能对多个不同的字符数组或字符指针输入。
其实手动一个字符一个字符的输入(循环每次输入一个字符,由name[i]接收,最后手动加一个'/0')也行只是比较麻烦,不在讨论。
第三个问题:
只要记得凡是对字符串的整体性操作都是接收字符串的首地址,就很容易了,像输出拷贝等。