strcat strcpy 深入研究(解决乱码等问题)
strcat是将一个字符串链接到另外一个字符串上的函数,具体形式如下:
char* strcat(char* dest,const char* src)
函数的具体流程如下:
1.先查找dest字符串的结尾(即'\0')
2.然后从dest字符串的结尾位置(即'\0'所在的位置)开始,复制src中的字符(包括结尾'\0')。产生的结果是dest的结尾'\0'会被覆盖掉,最后产生一个新的结尾。
3.将dest返回(一般用不到)
注意事项
1.dest必须被初始化,即包含一个'\0'结尾。用malloc分配字符串时,经常发生没有初始化的错误。有时候也会正常执行,是因为分配到的内存中,第一个单元的内容刚好为'\0'。但是不能保证每次都这么好运。所以初始化还是有必要的。
可以这样进行初始化
char* str=(char*) malloc(sizeof(100));
*str='\0';//注意这里是单引号,以为*str表示str所在地址存储的一个char
或者
*str=0;
也可以这样strcpy(str,"");
2.src也必须初始化,包含一个'\0'的结尾,不过这个一般发生错误的概率较小,因为很多时候直接使用一个字符串做参数strcat(dest,"hello world.")。
3.dest所指向内存的大小必须>=strlen(dest)+strlen(src)+1,否则会发生不可知的错误,比如乱码。使用之前要先确认dest的空间足够大再使用strcat函数。
glibc中的源码 strcat.c
char *
strcat (dest, src)
char *dest;
const char *src;
{
char *s1 = dest;
const char *s2 = src;
reg_char c;
/* Find the end of the string. */
do
c = *s1++;
while (c != '\0');
/* Make S1 point before the next character, so we can increment
it while memory is read (wins on pipelined cpus). */
s1 -= 2;
do
{
c = *s2++;
*++s1 = c;
}
while (c != '\0');
return dest;
}
strcpy是将一个字符串复制到另外一个字符串地址上的函数,函数形式如下:
char* strcpy(char* dest,char* src)
函数流程
1.将src中的字符(包括结尾'\0')一个个复制到dest中,dest原来的字符将被覆盖掉。
2.将dest指针返回
注意事项:
1.dest可以不初始化,比如
char *str=(char*) malloc(sizeof(char)*100);
strcat(str,"hellow world!");
2.利用这一特性,可以用来初始化字符串变量
strcat(str,"");将达到和
*str=0;一样的效果
glibc中strcpy.c的函数实现
char *
strcpy (dest, src)
char *dest;
const char *src;
{
reg_char c;
char *__unbounded s = (char *__unbounded) CHECK_BOUNDS_LOW (src);
const ptrdiff_t off = CHECK_BOUNDS_LOW (dest) - s - 1;
size_t n;
do
{
c = *s++;
s[off] = c;
}
while (c != '\0');
n = s - src;
(void) CHECK_BOUNDS_HIGH (src + n);
(void) CHECK_BOUNDS_HIGH (dest + n);
return dest;
}
有没有发现这个代码实现的很tricky,off是(dest的地址-src的地址-1)
c = *s++;
s[off] = c;
相当于
c = *s++;
dest++= c;
不过我感觉这样的代码格式不值得推荐,效率上一样,但是阅读性更差。让人很难看懂。下面就扯两句,代码写的让人看得懂,比少些几行,提高一点点效率更重要。更何况,很多时候经过编译器的优化,少些的那几行不见得更高效。具体的可以看看《重构 改善既有代码的设计》这本书。先声明一下,我不是卖书的,和这本书的作者没有一毛钱关系:-D。
本文由ladd原创,欢迎转载,但请注明出处: