字符串[2]:自定义函数实现字符串API操作(1)

原创首发于CSDN,转载请注明出处,谢谢!https://blog.csdn.net/weixin_46959681/article/details/116277742


前言

在程序员进行面试时,笔试环节会经常要求自定义函数封装实现相关的 字符API ,来考察面试的程序员对编程的理解和编程水平。从这个层面考虑,我们需要也有必要不调用的系统提供的API,而是自己自定义函数实现与系统API同样的功能。


自定义函数实现字符串API操作(1)

|puts() —— myPuts()

函数原型:

#include <stdio.h>
// 返回值为一个整数(可以自行验证)。
int puts(const char *string)

演示代码: myPuts.c

/* myPuts.c */
#include <stdio.h>

void myputs(char *p) //取内容符号,非指针。
{
        printf("myPuts:");
        while(*p != '\0' ){
        //      putchar(*p++);
        		printf("%c",*p++);
        }
        putchar('\n');
}

int main()
{
        char p[] = "hello,world!";

        int i = puts(p);
        printf("puts(p):%d\n",i);
        myputs(p);

        return 0;
}

运行结果:
在这里插入图片描述

|gets() —— myGets()

函数原型:

#include <stdio.h>
//返回值为一个字符型指针。
char *gets(char *str);

演示代码: myGets.c

/* myGets.c */
#include <stdio.h>

//除指针的声明之外,一切都为取内容运算符。
int myGets(char *p) 
{
        int cnt = 0;
        while( *p = getchar() ) 
        {
                if(*p == '\n'){
                        return cnt;
                }else{
                        cnt++;
                        p++;
                }
        }
        return cnt;
}

int main()
{
        //开辟字符串空间。
        char str[128] = {'\0'};

        printf("请输入你的字符串:\n");
        int n = myGets(str);
        printf("输入的字符数为 %d\n",n);
        printf("myGets:%s",str);
        
        return 0;
}

运行结果:
myPuts.c

碎碎念:

  • 没什么编程能力,代码调试起来太费劲,1小时的功夫搭进去了。教学视频中自定义函数部分的上一段代码的逻辑不成立。因为主函数中所定义的字符串str 已经被初始化了 \0,不需要再次判定指针是否为 NULL 了。直接砍掉上半段,下半段原封不动,改来改去也是 bug 不断。 😞😞😞

|strlen() —— myStrlen()

函数原型:

#include <string.h>
// 返回值为一个整型数值。
size_t strlen(const char *str)

演示代码: myStrlen.c

/* myStrlen.c */
#include <stdio.h>

int myStrlen(char *p)
{
        int cnt = 0;
        printf("myStrlen:");
        while(*p++ != '\0'){
                cnt++;
        }
        return cnt;
}

int main()
{
        //读者可以自行结合上文的myGets,或者使用gets。
        //编译器自动在字符串末尾添加空字符 '\0'。
        char q[] = "hello,world!";
        char *ret = NULL;

        myStrlen(q);
        printf("%d byte.\n",ret);
        return 0;
}

运行结果:
myStrlen.c

注意⚠️: 可以看到与 myPuts() 中的统计数相比(12 —— 13),少了一个空字符 ‘\0’

|memset() —— myMemset()

函数原型:

# include <string.h>
//返回值为一个无类型的指针。
void *memset(void *s, int c, unsigned long n);

演示代码: myMemset.c

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

//使用 myMemset 或者 *myMemset 都可以。
void *myMemset(char *q, char c, int size)
{
        while(size){
        		//指针指向数组字符的首字符,下面同步减少。
                *q = c;
                q++;
                size--;
        }
}

int main()
{
        //memset原始用法。
        char *p = NULL;
        p = (char *)malloc(128);
        memset(p,'a',128);
        printf("memset: %s\n",p);

        //myMemset
        myMemset(p,'A',128);
        printf("myMemset: %s\n",p);
        return 0;
}

运行结果:
myMemset.c

|strcpy() —— myStrcpy()

函数原型:

#include <string.h>
//返回值为一个字符型的指针。
char *strcpy(char* dest, const char *src);

演示代码: myStrcpy.c

/* myStrcpy.c */
#include <stdio.h>
#include <string.h>

char *myStrcpy(char *dest, const char *src)
{
        if(dest == NULL || src == NULL){
                return NULL;
        }

        while(*src != '\0'){
                *dest++ = *src++;
        }
        return dest;
}

//该函数只拷贝 hello 5个字符。
char *myStrncpy(char *dest, const char *src, int n)
{
        if(dest == NULL || src == NULL){
                return NULL;
        }

        //只有当n大于零时,条件才成立。
        while(*src != '\0' && n > 0){
                *dest++ = *src++;
                n--;
        }
        return dest;
}

int main()
{
        char dest[128] = {'\0'};
        char *src = "Hello,world!";

        strcpy(dest,src);
        printf("strcpy test: %s\n",dest);

        memset(dest,'\0',128);

        myStrcpy(dest,src);
        printf("myStrcpy test: %s\n",dest);

        memset(dest,'\0',128);

        myStrncpy(dest,src,5);
        printf("myStrncpy test: %s\n",dest);
        return 0;
}

运行结果:
myStrncpy.c

|strcat() —— myStrcat()

函数原型:

#include <string.h>
//返回值为一个字符型的指针。
char *strcat(char *dest, const char *src);

演示代码: myStrcat.c

/* myStrcat.c */
#include <stdio.h>
#include <string.h>

char *myStrcat(char *dest, const char *src)
{
        //dest遍历跑到尾部。
        while(*dest != '\0'){
                dest++;
        }
		//两个指针一起操作,*dest必须要先跑到尾巴,后*src再赋值。
        while(*src != '\0'){
                *dest++ = *src++;
        }
        return dest;
}

int main()
{
        int i = 0;

        char dest[20] = "111111";
        char src[] = "222222";
		
		//使用函数strcat(*dest,*src)时必须保证前一个参数的空间必须能包容后者,否则溢出报错。
        strcat(dest,src);
        printf("strcat test: %s\n",dest);
		
		//目的是在二次拼接之间显示出对比并且处理了其余的字符。
        memset(dest,'1',6);
        for(i=6;i<=20;i++){
                dest[i] = '\0';
        }

        myStrcat(dest,src);
        printf("myStrcat test: %s\n",dest);
        return 0;
}

运行结果:

第一次第二次
在这里插入图片描述在这里插入图片描述

吐槽

虽然仅仅只有六个字符API,但是笔者即便是跟着视频过了一篇就已经耗费了一整天的时间(中间找出一些小小的错误,外加根据自己对C语言的理解更改了代码)。即便如此,仍然还剩余6个API没有完成,strupr()strlwr()strtok()strchr()strstr()strcmp()

博客的排版、代码出 Bug 时的调式、代码的更改、思考花费的时间、按照顺序编译截图(多的时候甚至四五次)…… 当深入这些琐碎的细节时,看得人头晕眼花,内心的焦躁和不耐烦接连滋生,但笔者还是克制住了。成果的展示是简洁和优美的,但这背后的工作量已经让本人的肩膀酸麻了。(看到这里你还不点赞吗……)

文章已经五千字一百多字了,笔者不打算继续写了。这些剩余的API笔者会将其放到第三篇里去,未来空闲时再把这个尾巴补上吧。除非你有大把充裕的时间,不然千万别像笔者一天内干出一篇博文……


参考资料


更新时间记录

  • 文章首次发布。「2021.4.29 21:39:52」
  • “gets() —— myGets()”一节完成。 「2021.5.2 11:34」
  • “memset —— myMemset.c ”一节完成。 「2021.5.2 14:26」
  • 把从一到四的函数原型补全。 「2021.5.2 18:51」
  • “strcpy() —— myStrncpy()”一节完成。 「2021.5.2 20:00」
  • “strcat() —— myStrcat()”一节完成。 「2021.5.2 20:37」
  • “吐槽”一节完成。 「2021.5.2 20:58」
  • “前言”一节完成。 「2021.5.2 21:33」
  • 修改了代码中的小瑕疵,增加了些许代码注释。 「2021.5.3 20:28」
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值