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 除了添加了一个参数之外, 还加入了根据这个参数进行检测的功能, 检测数据的有效性, 以及回滚操作。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-29 19:11:08

C语言中strcat的实现方法的相关文章

C语言中的union使用方法

union共用声明和共用一变量定义: "联合"是一种特殊的类.也是一种构造类型的数据结构.在一个"联合"内能够定义多种不同的数据类型. 一个被说明为该"联合"类型的变量中,同意装入该"联合"所定义的不论什么一种数据,这些数据共享同一段内存, 以达到节省空间的目的(另一个节省空间的类型:位域). 这是一个很特殊的地方,也是联合的特征. 另外,同struct一样,联合默认訪问权限也是公有的,而且,也具有成员函数. 共用体(參考&q

浅析C语言中assert的用法(转)

原文地址:http://www.jb51.net/article/39685.htm 以下是对C语言中assert的使用方法进行了介绍,需要的朋友可以参考下. assert宏的原型定义在<assert.h>中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:#include <assert.h>void assert( int expression );assert的作用是先计算表达式expression,如果其值为假(即为0),那么它先向标准错误流stderr打印一条出错

java 程序语言中的LinkedList 集合基本方法演示

java 程序语言中的LinkedList 集合基本方法演示 import java.util.Iterator; import java.util.LinkedList; public class LinkedListDemos { public static void main(String[] args) { // 新建一个容器 LinkedList link = new LinkedList(); link.addFirst("abc1"); link.addFirst(&qu

php语言中Excel表格导入数据库的方法详解

在php编程语言中,对于如何在Excel表格中导入数据库的方法是很多编程者比较头疼的一个问题,有些技术人员可能在百度尝试过搜索很多不同的问题,但是给出的答案经过自己测试之后,发现还是行不通,那么对此,燚轩科技也尝试了一下如何在Excel表格中导入数据库,现在将源代码展示给各位技术编程者,大家可以借鉴参考一下. public function saveexcel(){require_once('./Thinkphp/Extend/Vendor/PHPExcel-1.8/Classes/PHPExc

在Swift语言中,关于Any,AnyObject,AnyClass的区别与联系

在Swift语言中,协议定义类或结构体应该遵守的变量和方法集合,如下所示,这个一个标准的协议的声明: protocol NSObjectProtocol { func isEqual(object: AnyObject?) -> Bool var hash: Int { get } var superclass: AnyClass? { get } func `self`() -> Self! func isProxy() -> Bool func isKindOfClass(aClas

GO语言中import的规则和用法

GO语言中引入包使用import,我将在本文讲解下规则和用法. 一些规则: 1.包中不能有main方法. 2.同文件夹中可以直接用方法名调用. 3.main函数建议放在package main里4.main不能调用同个目录下的其它文件中的方法. 5.还可以把包放在上级的目录中,如: /src/myFolder/foo/bar1.go #package foo /src/myFolder/foo/bar2.go #package foo /src/myFolder/foo/bar3.go #pac

Java语言中String累的总结

String类 1.Java.lang包简介 java.lang包是java内置的一个基础包,其中包含了一系列程序中经常要用到的类: 在默认情况下,每个java程序都会自动导入该包,因此无需在程序中显式地声明. 2.String类 Java语言中,字符串是String类的对象: Java语言中,String是引用数据类型: 可以通过使用String类提供的方法来完成对字符串的操作: 创建一个字符串对象之后,将不能更改构成字符串的字符: 每当更改了字符串版本时,就创建了一个新的字符串对象,并在其内

C语言中,头文件和源文件的关系(转)

简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程: 1.预处理阶段 2.词法与语法分析阶段 3.编译阶段,首先编译成纯汇编语句,再将之汇编成跟CPU相关的二进制码,生成各个目标文件 (.obj文件)4.连接阶段,将各个目标文件中的各段代码进行绝对地址定位,生成跟特定平台相关的可执行文件,当然,最后还可以用objcopy生成纯二进制码,也就是去掉了文件格式信息.(生成.exe文件) 编译器在编译时是以C文件为单位进行的,也就是

黑马程序员---C语言中的extern

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”. 1. extern修饰变量的声明.举例来说,如果文件a.c需要引用b.c中变量int v,就可以在a.c中声明extern int v,然后就可以引用变量v.这里需要注意的是,被引用的变量v的链接属性必须是外链接(external)的,也就是说a.c要引用到v,不只是取决于在a.c中