某日二师兄参加XXX科技公司的C++工程师开发岗位第31面:

面试官:strcpy函数使用过吧?

二师兄:用过。

面试官:这个函数有什么作用?

二师兄:主要用做字符串复制,将于字符从一个位置复制到另一个位置。

面试官:strncpy函数也使用过吧,和strcpy有何不同?

二师兄:strncpy多了一个size_t的参数,用于避免缓冲区溢出。

面试官:能否实现一个strncpy函数?

二师兄:好的。

void strncpy(char *dest, char *src, size_t n)
{
for (size_t i = 0; i < n; i++)
{
*(dest + i) = *(src + i);
}
}

面试官:额。。如果strlen(src) < n会发生什么?

二师兄:嗯。。那要做个判断。。

void strncpy(char *dest, char *src, size_t n)
{
size_t len = strlen(src) > n ? n : strlen(src);
for (size_t i = 0; i < len; i++)
{
*(dest + i) = *(src + i);
}
}

面试官:如果strlen(dest) < n呢?

二师兄:因为n是程序员传入进来的,且无法知晓dest的长度,所以这个n要程序员保证它的正确性。

面试官:有没有更简洁的写法?比如利用指针的自增?

二师兄:让我想想。。

void strncpy(char *dest, char *src, size_t n)
{
while(n-- && (*dest++ = *src++));
}

面试官:如果用户传入的src是字符串常量,会发生什么?

二师兄:额。。。让我想想。。明白了,要在src前加上const修饰符:

void strncpy(char *dest, const char *src, size_t n)
{
while(n-- && (*dest++ = *src++));
}

面试官:有一些操作需要strcpy嵌套strcpy,如果要实现这个功能,需要做哪些修改?

二师兄:你说的是strncpy(strncpy(...)...)这种操作吗?

面试官:是的。

二师兄:那么需要返回dest地址:

char *strncpy(char *dest, const char *src, size_t n)
{
char *ret = dest;
while (n-- && (*dest++ = *src++));
return ret;
}

面试官:如果srcdest的内存地址有重叠,会发生什么?

二师兄:这要分为两种情况,第一种情况:dest < src < dest+n

二师兄:此时并不需要特殊的处理,拷贝完成后,整个字符串是这样的:

二师兄:虽然src被覆写了,但是dest的内容是正确的。

二师兄:第二种情况,src < dest <src+n;

二师兄:如果直接拷贝,结果会变成这样:

二师兄:此时dest的内容是错误的。所以我们需要对这种情况做特殊处理:

char *strncpy(char *dest, const char *src, size_t n)
{
char *ret = dest;
size_t len = strlen(src) > n ? n :strlen(src);
if(src < dest && dest < src + len) //需要从尾部开始拷贝
{
const char* s = src + len - 1;
char* d = dest + len - 1;
while(len --) *d-- = *s--;
return ret;
}
while (n-- && (*dest++ = *src++));
return ret;
}

面试官:嗯。有没有什么办法对以上的代码做一些性能上的优化?

二师兄:可以使用SIMD(Single Instruction Multiple Data)指令对strncpy函数做一些优化。*dest++ = *src++每次只能复制一个字节的内容,而SIMD每次可以复制超过一个字节的内容,当数据量大的时候,效率会有明显的提升。

面试官:写过SIMD相关的代码吗?

二师兄:只是听说过,没有用过。

面试官:好的,今天就到这里,请回去等通知吧。

什么是SIMDSIMD真的能够提升效率吗?

SIMD是一种常见的并行计算技术,一条指令可以同时处理多个数据,所以它可以减少指令的数量,从而提高处理速度。

X86_64架构下,SIMD的指令集主要包括MMXSSEAVX

下面代码演示如果使用SIMD技术加速大容量字符串的拷贝:

#include <emmintrin.h>
void strncpy_simd(char *dest, const char *src, size_t n)
{
size_t len = strlen(src) > n ? n : strlen(src);
__m128i *d = (__m128i *)dest;
const __m128i *s = (const __m128i *)src;
while (len >= sizeof(__m128i))
{
_mm_storeu_si128(d++, _mm_loadu_si128(s++));
len -= sizeof(__m128i);
}
char *dc = (char *)d;
const char *sc = (const char *)s; while (len--)
{
*dc++ = *sc++;
}
}

今天的面试到这里就结束了,感谢大家的耐心~

关注我,带你21天“精通”C++!(狗头)

C++面试八股文:如何实现一个strncpy函数?的更多相关文章

  1. 《面试八股文》之kafka21卷

    微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是moon,最新一篇面试八股文系 ...

  2. strncpy函数使用

    strncpy()函数原型:extern char *strncpy(char *dest, char *src, int n);    用法:#include <string.h>    ...

  3. strcpy函数和strncpy函数的区别

    strcpy函数和strncpy函数的原型介绍在我的另一篇文章中介绍了,见strcpy,strncpy,strlen等函数原型 strcpy:字串复制 原型:char *strcpy(char *de ...

  4. strlen函数,strcat函数,strcpy函数,strncpy函数,strcmp函数

    strcpy函数: char *strcpy(char *Dest , const char *Src) { assert((Dest != NULL) && (Src != NULL ...

  5. 《面试八股文》之 Redis 16卷

    微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. redis 作为 ...

  6. 《面试八股文》之 JVM 20卷

    微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. <面试八股 ...

  7. 请写一个php函数,可以接受任意数量的参数

    请写一个php函数,可以接受任意数量的参数 这是一道面试题.怎么写这个函数呢? function fun(......) { } ----------------------------------- ...

  8. 在String()构造器不存在的情况下自定义一个MyString()函数,实现如下内建String()方法和属性:

    在String()构造器不存在的情况下自定义一个MyString()函数,实现如下内建String()方法和属性: var s = new MyString("hello"); s ...

  9. 如何实现一个malloc函数

    一.概述 1.malloc简介 函数所在头文件:<stdlib.h> 函数原型是:void *malloc (size_t n) 函数功能:在内存的动态存储区中分配一个长度为size的连续 ...

  10. 研究不定数量参数的函数并实现一个printf函数

    一.前提知识 1.如何传递参数(主函数) a.函数的参数是通过栈传递,而且是从右到左依次入栈 b.即使是char型变量,在传递参数时,也是占用两个字节,因为push操作是两个字节为单位的. c.sho ...

随机推荐

  1. 系统建模之UML用例视图

    <用例视图> 1 用例图的目标 who「参与者」:确定谁要使用系统 what「功能」:他们使用系统做什么? 2 用例图-四大主要组件 2.1 参与者 参与者:与应用程序或系统进行交互的用户 ...

  2. [Linux]常用命令之【du/fdisk/df/ls】#磁盘管理/文件管理#

    本文的经典应用场景: 1.查找占用磁盘存储空间最大的目录/文件 2.关于[磁盘分区]的相关概念和实操,详见另一博文:[Linux]磁盘分区 - 博客园/千千寰宇 1 fdisk fdisk := &q ...

  3. [Linux]RabbitMQ - 解决Error: unable to connect to node rabbit@localhost: nodedown

    1 问题 环境: CentOS7.8.2003 (x86 / 64bit) 版本: RabbitMQ 3.6.15 (Erlang 19.3) 安装方式: 二进制源码压缩安装 2 解决思路 2.1 思 ...

  4. Exception-List

    一.500错误:找不到 jar包 应用根目录/WEB-INF/lib目录中没有对应的jar包. ctrl+shift+alt+s,打开artifacts,发现outputRoot里缺少lib目录.添加 ...

  5. DG修复:清理归档配置归档清理脚本

    问题描述:DG同步断了十天,发现FRA归档盘符满了.需要清理下,重新增量恢复DG Error 12528 received logging on to the standby FAL[client, ...

  6. Nucleistudio+Vivado协同仿真教程

    创建Vivado工程 1.创建工程: 在Vivado中创建工程,命名随意,路径随意: 2.配置工程: 这里可以选择是否添加源文件等,我们先不添加: 3.选择FPGA核心: 选择MCU200T对应的FP ...

  7. 玩转云端 | 算力基础设施升级,看天翼云紫金DPU显身手!

    数字时代下,算力成为新的核心生产力,传统以CPU为核心的架构难以满足新场景下快速增长的算力需求,具备软硬加速能力的DPU得以出现并快速发展.天翼云凭借领先的技术和丰富的应用实践自研紫金DPU,打造为云 ...

  8. Caused by: java.net.BindException: Address already in use: JVM_Bind(ActiveMq已经启动)

    1.本地启动项目开启两个启动类出错. Error creating bean with name 'brokerService' defined in class path resource [com ...

  9. 【介绍】C++五种迭代器

    目录 1. 输入迭代器(Input Iterator): 2. 输出迭代器(Output Iterator): 3. 前向迭代器(Forward Iterator): 4. 双向迭代器(Bidirec ...

  10. ES6 新增数组,对象,字符串的方法

    1,ES6+ 新增数组方法 Array.from Array Array.from(arrayLike[, mapFn[, thisArg]]) 将类数组(伪数组)转换成数组 参数: arrayLik ...