实现

金山面试的问题之一,比较简单。
需要注意两点:1.字符串空间检测判断2.字符串末尾记得加'0'

第一种写法:

也是我的答案:

char *strcat(char *str1, char *str2)
{
    if((str1==NULL)||(str2==NULL)) throw "Invalide arguments!";

    int len1=strlen(str1),len2=strlen(str2);
    for(int i=strlen(str1);i<len1+len2;i++){
        str1[i]=str2[i-len1];
    }
    str1 [len1+len2]= '\0';
    return str1;
}

当时少写了 str1 [len1+len2]= '0';

第二种写法:

char *strcat(char *str1, char *str2)
{
    if((str1==NULL)||(str2==NULL)) throw "Invalide arguments!";
    char *pt = str1;
    while(*str1!='\0') str1++;
    while(*str2!='\0') *str1++ = *str2++;
    *str1++ = '\0';
    return pt;
}

切不可写成return str1;
因为此时函数体内的str1指针已经被移动到字符串结尾,指向'0'。
所以只能返回一开始pt保存的原始str1。返回值错误!

由于函数strcat的参数str1是形参,所以主函数的数组a的指针不会变化。
但是最好的写法还是不要直接对str1做修改:

char *strcat(char *str1, char *str2)
{
    if((str1==NULL)||(str2==NULL)) throw "Invalide arguments!";
    char *pt = str1;
    while(*pt!='\0') pt++;
    while(*str2!='\0') *pt++ = *str2++;
    *pt = '\0';
    return str1;
}

应用

参考:http://www.blog.chinaunix.net...
声明:使用gcc和vc++(VS2010)编译

函数定义:char *strcat (char *dest,const char *src)
函数说明:strcat()会将参数src字符串拷贝到参数dest所指的字符串尾,第一个参数dest要有足够的空间来容纳要拷贝的字符串;
返回值: 返回dest字符串参数的起始地址;

接下来分三种情况来看strcat()函数:

方案一:两个参数都是数组

#include <string.h>
#include <stdio.h>

int main(void)
{
    char dest[30] = "Hello";
    char src[] = "World";

    strcat(dest, src);
    printf("dest:[%s]\n", dest);

    return 0;
}

GCC/VC++:dest:[HelloWorld]

方案二:两个参数都是指针

  1. dest为空

    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
        char *dest = NULL;
        char *src = "World";
    
        strcat(dest, src);
        printf("dest:[%s]", dest);
    
        return 0;
    }

    GCC:Segmentation fault (core dumped)竟然是段错误,为什么呢?

    dest没有足够的空间来存储src中的内容;

    VC++:

    cmd:空
    弹出:.exe已停止工作。
    

    修改之后的:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(void)
    {
        char *dest = NULL;
        dest = (char *)malloc(1024);
        *dest='\0';//显式将首地址指向结束符。非常必要。否则1024个字节的字符串会充满随机的字符。
        char *src = "World";
    
        strcat(dest, src);
        printf("dest:[%s]", dest);
    
        return 0;
    }

    GCC/VC++:dest:[World]
    如果没有*dest='\0';,GCC通过,VC++不通过。
    猜测:gcc在malloc后,新分配的空间自动补全了'0'。

  2. dest非空

    但此时的dest是空字符串,如果想要在非空字符串(比如"aaa")后strcat怎么办?
    直接把char *dest = NULL;改成char *dest = "aaa";吗?

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(void)
    {
        char *dest = "aaa";
        dest = (char *)malloc(1024);
        *(dest+3)='\0';
        char *src = "World";
    
        strcat(dest, src);
        printf("dest:[%s]", dest);
    
        return 0;
    }

    VC++:

    cmd: dest:[屯蚖orld]

    gcc:

    dest[World]

    VC++中, "aaa"被新分配的内存地址的值覆盖。由于新分配的内存地址的值并未初始化(除了dest+3位置上赋值为'0'), 所以出现乱码。"World"的第一个字母W(1字节)被a的第三个字符组合成了汉字“蚖”(2字节)。

    那么,先分配内存,然后赋值:char *dest = (char *)malloc(1024);dest = "aaa";?
    一样不可以!
    VC++:

    cmd:空
    弹出:.exe已停止工作!

    gcc:Segmentation fault (core dumped)
    原因相同:"aaa"将分配的空间覆盖,也就是说a指向新的字符串"aaa",它的大小为4,无法放下a和b。

    正确的做法是对a先申请内存,然后用strxxx函数对a开始几位进行修改。比如用strcpy:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    int main ()
    {
        char *dest=(char *)malloc(1024);
        char *src="World";
        strcpy (dest,"aaa");
        strcat (dest,src);
        printf("dest:[%s]", dest);//puts (dest);
        return 0;
    }

    vc++:

    cmd:dest:[aaaWorld]

    gcc:

    dest:[aaaWorld]

    OK!

方案三:第一个是数组,第二个是指针

#include <stdio.h>
#include <string.h>

int main(void)
{
    char dest[6] = "Hello";
    char *src = "World";

    strcat(dest, src);
    printf("dest:[%s]\n", dest);

    return 0;
}

gcc:

dest:[HelloWorld]
*** stack smashing detected ***: ./1 terminated
Aborted (core dumped)

为什么会这样呢?不是说要空间足够的时候才可以拷贝成功的么?
很明显,这属于数组越界的问题,在C语言中,c不检查也不提示,所以这里的拷贝用到了dest[6]后面紧挨着的几个存储单元;

VC++:

cmd:dest:[HelloWorld]
弹出:stack around the variable “XX” was corrupted!

方案四:第一个指针,第二个数组

#include <stdio.h>
#include <string.h>

int main(void)
{
    char *dest;
    char src[] = "World";

    strcat(dest, src);
    printf("dest:[%s]\n", dest);

    return 0;
}

看到这里,都会知道肯定是dest的空间不足,无法拷贝src中的内容;
所以输出结果是:
gcc:

dest:[�Ax�World]
//原文说他的结果是Segmentation fault (core dumped)

vc++:

cmd:空。
弹出:dest未初始化就被使用。

更改之后:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char *dest;
    dest = (char *)malloc(1024);
    *dest='\0';
    char src[] = "World";
    
    strcat(dest, src);
    printf("dest:[%s]\n", dest);

    return 0;
}

OK输出结果是
GCC/vc++:dest:[World]
如果没有*dest='\0';,GCC通过,VC++不通过。


peixn
78 声望2 粉丝