C语言中strcat的实现方法

最近看到一道题目要求, 自己码代码实现strcat的功能, 于是自己实现了一个如下:


/* * 12.编写一个函数JOIN,让它实现字符串连接运算功能。 */

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

// ==============【自己实现的strcat】==============
char * join(char * str1, const char * str2)
{
    assert(str1 != NULL && str2 != NULL);

    char * pstr = str1;
    while (*pstr++);
    --pstr;

    while ((*pstr++ = *str2++) != 0);

    return str1;
}

int main()
{
#define N 20

    char buf[N] = "hello ";
    char * str2 = "world!";
    char buf1[N] = "hello ";

    char * res = join(buf, str2);
    char * res1 = strcat(buf1, str2);

    printf("%s\n", res);
    printf("%s\n", res1);

    return 0;

}

因为, 我们知道这个函数输入的第一个字符串是需要有足够内存空间的, 如果空间不够, 会引起栈崩溃的情况
这里写图片描述

于是我们试图查看一下标准库中的写法,下面是标准strcat.c的实现代码

/***
*strcat.c - contains strcat() and strcpy()
* * Copyright (c) Microsoft Corporation. All rights reserved.
* *Purpose:
* Strcpy() copies one string onto another.
* * Strcat() concatenates (appends) a copy of the source string to the
* end of the destination string, returning the destination string.
* *******************************************************************************/

#include <cruntime.h>
#include <string.h>

#ifndef _MBSCAT
#pragma function(strcat,strcpy)
#endif /* _MBSCAT */

/***
*char *strcat(dst, src) - concatenate (append) one string to another
* *Purpose:
* Concatenates src onto the end of dest.  Assumes enough
* space in dest.
* *Entry:
* char *dst - string to which "src" is to be appended
* const char *src - string to be appended to the end of "dst"
* *Exit:
* The address of "dst"
* *Exceptions:
* *******************************************************************************/

char * __cdecl strcat (
 char * dst,
 const char * src
 )
{
 char * cp = dst;

 while( *cp )
 cp++; /* find end of dst */

 while( *cp++ = *src++ ) ; /* Copy src to end of dst */

 return( dst ); /* return dst */

}


/***
*char *strcpy(dst, src) - copy one string over another
* *Purpose:
* Copies the string src into the spot specified by
* dest; assumes enough room.
* *Entry:
* char * dst - string over which "src" is to be copied
* const char * src - string to be copied over "dst"
* *Exit:
* The address of "dst"
* *Exceptions:
*******************************************************************************/

char * __cdecl strcpy(char * dst, const char * src)
{
 char * cp = dst;

 while( *cp++ = *src++ )
 ; /* Copy src over dst */

 return( dst );
}

很明显, 原始的strcat函数是没有对 可能出现的各种问题做检查的。也就是说,如果我们输入一个空指针, 程序是会直接崩溃掉的<-_->!!
难怪现在推出了一个strcat_s版本。

/***
*strcat_s.c - contains strcat_s()
* * Copyright (c) Microsoft Corporation. All rights reserved.
* *Purpose:
* strcat_s() concatenates (appends) a copy of the source string to the
* end of the destination string.
* *******************************************************************************/

#include <string.h>
#include <internal_securecrt.h>

#define _FUNC_PROLOGUE
#define _FUNC_NAME strcat_s
#define _CHAR char
#define _DEST _Dst
#define _SIZE _SizeInBytes
#define _SRC _Src

#include <tcscat_s.inl>

其中tcscat_s.inl内容如下

/*** *tcscat_s.inl - general implementation of _tcscpy_s * * Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: * This file contains the general algorithm for strcat_s and its variants. * ****/

_FUNC_PROLOGUE
errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)
{
    _CHAR *p;
    size_t available;

    /* validation section */
    _VALIDATE_STRING(_DEST, _SIZE);
    _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);

    p = _DEST;
    available = _SIZE;
    while (available > 0 && *p != 0)
    {
        p++;
        available--;
    }

    if (available == 0)
    {
        _RESET_STRING(_DEST, _SIZE);
        _RETURN_DEST_NOT_NULL_TERMINATED(_DEST, _SIZE);
    }

    while ((*p++ = *_SRC++) != 0 && --available > 0)
    {
    }

    if (available == 0)
    {
        _RESET_STRING(_DEST, _SIZE);
        _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
    }
    _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
    _RETURN_NO_ERROR;
}

很明显可以看到, strcat_s 除了添加了一个参数之外, 还加入了根据这个参数进行检测的功能, 检测数据的有效性, 以及回滚操作。

你可能感兴趣的:(c)