最近看到一道题目要求, 自己码代码实现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 除了添加了一个参数之外, 还加入了根据这个参数进行检测的功能, 检测数据的有效性, 以及回滚操作。