1. str*系列手写代码

a. 一定要注意末尾'\0'的处理,切记切记

b. 一定要对输入做有效性判断,多用断言就是了

int Strlen(const char* str) {
assert(str != NULL);
const char* tmp = str;
while (*tmp != '\0') {
++tmp;
}
return tmp - str;
} char* Strcpy(char* dst, const char* src) {
assert(dst != NULL && src != NULL);
char* tmp = dst;
while (*src != '\0') {
*tmp++ = *src++;
}
*tmp = '\0';
return dst;
} char* Strncpy(char* dst, const char* src, int len) {
assert(dst != NULL && src != NULL && len >= );
char* tmp = dst;
for (; len > && *src != '\0'; --len) {
*tmp++ = *src++;
}
for (; len > ; --len) {
*tmp ++ = '\0';
}
return dst;
} char* Strcat(char* dst, const char* src) {
assert(dst != NULL && src != NULL);
char* tmp = dst;
while (*tmp != '\0') {
++tmp;
}
while (*src != '\0') {
*tmp++ = *src++;
}
*tmp = '\0';
return dst;
} char* Strncat(char* dst, const char* src, int len) {
assert(dst != NULL && src != NULL && n >= );
char* tmp = dst;
while (*tmp != '\0') {
++tmp;
}
for (; len > && *src != '\0'; --len) {
*tmp++ = *src++;
}
*tmp = '\0';
return dst;
} int Strcmp(const char* str1, const char* str2) {
assert(str1 != NULL && str2 != NULL);
for (; *str1 == *str2; ++str1, ++str2) {
if (*str1 == '\0') {
return ;
}
}
if (*(unsigned char*)str1 < *(unsigned char*)str2) {
return -;
} else {
return ;
}
} int Strncmp(const char* str1, const char* str2, int len) {
assert(str1 != NULL && str2 != NULL && len >= );
for (; len > ; ++str1, ++str2) {
if (*str1 != *str2) {
return ((*(unsigned char*)str1) < (*(unsigned char*)str2) ? - : );
} else if (*str1 == '\0') {
return ;
}
}
return ;
} char* Strchr(const char* str, int c) {
assert(str != NULL);
const char* tmp = str;
const char ch = (const char)c;
for (; *tmp != ch; ++tmp) {
if (*tmp == '\0') {
return NULL;
}
}
return (char*)tmp;
} char* Strstr(const char* str1, const char* str2) {
assert(str1 != NULL && str2 != NULL);
if (*str2 == '\0') return str1;
const char* tmp1 = str1;
const char* tmp2 = str2;
int len1 = Strlen(str1);
int len2 = Strlen(str2);
int i = ;
for (tmp1 = str1; i <= len1 - len2 && *tmp1 != '\0'; ++tmp1, ++i) {
if (*tmp1 != *tmp2)
continue;
const char* cur1 = tmp1;
const char* cur2 = tmp2; while (*cur1 == *cur2) {
++cur1;
++cur2;
if (*cur2 == '\0') {
return (char*)tmp1;
}
}
}
return NULL;
}

2. mem*系列手写代码

一定要对输入做有效性判断,多用断言就是了

void* Memchr(const void* src, int c, int len) {
assert(src != NULL && len >= );
const unsigned char ch = c;
const unsigned char* tmp = (const unsigned char*)src;
for (; len > ; --len, ++tmp) {
if (*tmp == ch) {
return (void*)tmp;
}
}
return NULL;
} int Memcmp(const void* s1, const void* s2, int len) {
assert(s1 != NULL && s2 != NULL);
const unsigned char* tmp1 = (const unsigned char*)s1;
const unsigned char* tmp2 = (const unsigned char*)s2;
for (; len > ; --len, tmp1++, tmp2++) {
if (*tmp1 != *tmp2) {
return ((*tmp1 < *tmp2) ? - : );
}
}
return ;
} void* Memcpy(void* dst, const void* src, int len) {
assert(dst != NULL && src != NULL && len >= );
char* dstTmp = (char*)dst;
const char* srcTmp = (const char*)src;
for (; len > ; --len, ++dstTmp, ++srcTmp) {
*dstTmp = *srcTmp;
}
return dst;
} void* Memmove(void* dst, const void* src, int len) {
assert(dst != NULL && src != NULL && len >= );
char* dstTmp = (char*)dst;
const char* srcTmp = (const char*)src;
if (dstTmp > srcTmp && dstTmp < srcTmp + len) {
for (srcTmp += n, dstTmp += n; len > ; --len, --srcTmp, --dstTmp) {
*dstTmp = *srcTmp;
}
} else {
for (; len > ; --len, ++srcTmp, ++dstTmp) {
*dstTmp = *srcTmp;
}
}
return dst;
}

3. atoi函数

atoi函数的实现

class Solution {
public:
int atoi(const char *str) {
assert(str != NULL);
const char* curr = str;
const int maxRange = 10;
int tmp = ;
int num = ;
while(isspace(*curr)) {
++curr;
}
const char* start = nullptr;
char sign;
if (*curr == '-' || *curr == '+') {
sign = *curr;
++curr;
start = curr;
} else {
start = curr;
} while (isdigit(*curr)) {
tmp = num;
num = num * + (*curr - '');
++curr;
}
int len = ;
if (!isdigit(*curr)) {
len = curr - start;
}
--curr;
if (len > maxRange || num < num - *curr) {
if (sign == '-') {
return INT_MIN;
} else {
return INT_MAX;
}
}
if (sign == '-') num = -num;
return num;
}
};

4. std::string实现

c++ std::string的简易实现

class Mystring {
public:
Mystring() : data_(new char[]) {
*data = '\0';
} explicit Mystring(const char* str) : data_(new char[strlen(str) + ]) {
strcpy(data_, str);
} explicit Mystring(const Mystring& str) : data_(new char[str.size() + ]) {
strcpy(data_, str.c_str());
} ~Mystring() {
delete[] data_;
} // 重载赋值,采用copy and swap手法,旧式写法
Mystring& operator=(const Mystring& str) {
Mystring tmp(str);
swap(tmp);
return *this;
} // 重载赋值,采用copy and swap手法,新式写法
Mystring& operator=(Mystring& str) {
swap(str);
return *this;
} int size() const {
return (int)strlen(data_);
}
const char* c_str() const {
return data_;
} void swap(Mystring& str) {
std::swap(data_, str.data_);
}
private:
char* data_;
};

a. Mystring类能够类似内置类型int一样,可以定义变量,可以复制,赋值

b. Mystring可以用作函数参数以及返回值类型

c. Mystring可以用作标准库容器的元素类型,即 vector/list/deque 的 value_type

d. 利用RAII正确管理资源,只在构造函数里调用 new char[],只在析构函数里调用 delete[]

e. 重载赋值运算符使用copy and swap 手法

5. Str进行大数计算

博文:大数相乘

class Solution {
public:
string multiply(string num1, string num2) {
if (num1.size() == || num2.size() == ) return "";
reverse(num1.begin(), num1.end());
reverse(num2.begin(), num2.end()); vector<int> result(num1.size() + num2.size(), );
int count = ;
for (int i = ; i < num1.size(); ++i) {
for (int j = ; j < num2.size(); ++j) {
result.at(i+j) += (num1.at(i) - '') * (num2.at(j) - '');
}
}
for (int i = ; i < result.size(); ++i) {
int tmp = result.at(i) + count;
result.at(i) = tmp % ;
count = tmp / ;
} int zeroPos = ;
for (zeroPos = result.size() - ; zeroPos >= ; --zeroPos) {
if (result.at(zeroPos) != ) break;
}
result.erase(result.begin() + zeroPos + , result.end());
reverse(result.begin(), result.end()); string res(result.size(), '');
for (int i = ; i < result.size(); ++i) {
res.at(i) += result.at(i);
} if (res == "") {
return "";
} else {
return res;
}
}
};

6. 为什么要禁止 char* p = "hello"这种写法?

学习C语言的同学肯定见过 char* p = "hello"这种写法的,现在我想说的是:千万不要这样写

int main() {
char* p1 = "hello";
char* p2 = "hello";
char p3[] = "hello";
char p4[] = "hello";
fprintf(stdout, "%p:%p\n", p1, p2);
fprintf(stdout, "%p:%p\n", p3, p4);
return ;
}

程序结果显示:p1等于p2,p3不等于p4

p1等于p2:"hello"为字符串常量,位于全局的const区域段,第一,它是常量const,不能被修改  第二,它是全局的,即所有指向"hello"的指针的地址值全都是一样的

p3不等于p4:p3和p4是字符数组,位于栈上,并且字符数组里的字符是可以被修改的

小结一下:

    char* p1 = "hello";
char p3[] = "hello";

p1:所指向内容不可修改(全局const),p1指针可以修改(可以更改指向)

p3:所指元素可以修改(普通数组),p3不可修改(数组名作为指针时表示数组的首地址,肯定不能修改)

回到  char* p = "hello"

前面我们解释了,p所指向的内容不可修改,即 p是一个指向const的指针

const char* p1 = "hello";

为什么要加上const呢?

因为 char* p = "hello" 把 实际的 const char* 隐含转换为 char*,万恶的转型啊,且看一段代码:

    char* p1 = "this is wrong";
char* p2 = "hello world";
strcpy(p1, p2);

编译通过了,运行呢? core dump,哈哈

前面说过了,p1实际上 const char*, 你现在想通过p1来修改const,必须来一个core dump

但是,如果我们这样写呢?

    const char* p1 = "this is wrong";
const char* p2 = "hello world";
strcpy(p1, p2);

编译错误!!!  (注:我使用的是 g++ -Wall 编译)

小结一下:

char* p1 = "this is wrong"; // 将字符串常量的const特性隐式转型了,通过p1修改字符串时将产生 运行时错误
const char* p1 = "this is right"; //加上const明确表示字符串的const特性,通过p1修改字符串时将产生 编译时错误

既然上面用了 strcpy函数做例子,那就再说说strcpy的问题

假如对上述所提的问题都理解了,那就是以下的代码:

int main() {
char dst[] = "this is right";
const char* src = "hello world";
strcpy(dst, src);
fprintf(stdout, "%s", dst);
return ;
}

运行都挺好的,但是,我想说的是:不要使用strcpy这类函数

我们知道C语言标准库有: strcpy、strcat、strcmp

C标准库也有如下函数:strncpy、strncat、strncmp

以 strcpy strncpy为例

strcpy只有遇到src的'\0'才结束复制,根本不管dst的空间是不是足以容纳src,非常容易造成缓冲区溢出,各种××攻击纷至沓来

所以才有了 strcpy对应的“安全”版本--strncpy,strncpy原本想解决strcpy的不安全性,但是它的语义真是让人蛋疼

strncpy仅仅复制 src的前n个字节,如果src的前n个字节不包括结束符'\0',问题就出来了,根本不复制src的结束符.....真让人无语

使用strncpy一般是如下方式:

strncpy(dst, src, strlen(dst));

我要好offer之 字符串相关大总结的更多相关文章

  1. 我要好offer之 系统基础大总结

    1. APUE Unix环境高级编程 (1) Unix基础知识: 内核->系统调用->shell和库函数->应用软件 (2) 文件I/O:read函数返回值.进程的文件描述符表.文件 ...

  2. 我要好offer之 概率题大总结

    1. 利用等概率Rand5生成等概率Rand3 Rand5生成等概率Rand3 这个题目可以扩展为:利用等概率RandM生成等概率RandN (M > N) 这里,我们首先明白一个简单的知识点: ...

  3. 我要好offer之 排序算法大总结

    1. 插入排序 (1) 直接插入排序 void StraightInsertionSort(std::vector<int>& num) { || num.size() == ) ...

  4. 【Todo】字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树

    另开一文分析字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树. 先来一个汇总, 算法: 本文中提到的字符串匹配算法有:KMP, BM, Horspool, Sunday, BF, ...

  5. Java数据结构和算法总结-字符串相关高频面试题算法

    前言:周末闲来无事,看了看字符串相关算法的讲解视频,收货颇丰,跟着视频讲解简单做了一下笔记,方便以后翻阅复习同时也很乐意分享给大家.什么字符串在算法中有多重要之类的大路边上的客套话就不多说了,直接上笔 ...

  6. PHP基础系列(一) PHP字符串相关的函数分类整理

    PHP提供了非常丰富的自带函数,有人说PHP是一个大的函数库,在某种程度上我是非常认同这种观点的,这个也是PHP非常容易上手的原因之一.在使用PHP编程的时候,需要实现某一功能的时候,如果说php自带 ...

  7. python字符串、字符串处理函数及字符串相关操作

    python字符串.字符串处理函数及字符串相关操作 字符串介绍 python字符串表示 Python除处理数字外还可以处理字符串,字符串用单撇号或双撇号包裹: >>> 'spam e ...

  8. java常用类详细介绍及总结:字符串相关类、日期时间API、比较器接口、System、Math、BigInteger与BigDecimal

    一.字符串相关的类 1.String及常用方法 1.1 String的特性 String:字符串,使用一对""引起来表示. String声明为final的,不可被继承 String ...

  9. 常用linux 命令 -字符串相关

    参考网络文章,个人工作总结 题记:一般对字符串的操作有以下几种:求长度,截取字符串,拼接字符串,找字符串中某个字符的索引 1 expr 命令 1.1 定义 man 手册 Print the value ...

随机推荐

  1. overloading and overriding

    What is the difference between method overloading and method overriding in Java? Differences between ...

  2. centos7中文显示为小方块~~啊啊啊 求大佬们解答

    这个问题困扰我很久了,刚好前几天注册了博客园,就想问问大佬们是怎么解决中文显示小方块的? 我试了很多办法,包括但不限于修改i18n配置文件,locale.conf,添加中文字体库等等等... 但都没有 ...

  3. SSH程序框架之Spring与HIbernate整合

    spring整合hibernate 有两种方式 1.注解方式 2.xml方式实现 Spring整合Hibernate有什么好处? 1.由IOC容器来管理Hibernate的SessionFactory ...

  4. oracle系統表、數據字典介紹與日常問題診斷

    oracle系統表.數據字典介紹與日常問題診斷 數據字典是由唯讀的table和view組成的,產生於$oracle_home\rdbms\admin\catalog.sql.裡面儲存Oracle資料庫 ...

  5. Unity3d 中键值监听方法

    unity3d的api中没有负责监听键值的方法,不过unity的input类是通过c#类获取各类监听事件,所以我们可以通过c#类监听,方法如下: void OnGUI() { Event e = Ev ...

  6. POP简单动画简单使用 (入门级别)

    动画可以让APP“更友好”的与用户交互,苹果提供很多的好看的动画供开发者使用,不过简单的平移.旋转.缩放.......使用起来很简单,但是想要进行一些比较复杂的动画效果,使用起来就比较难以实现,俗话说 ...

  7. 为什么要在函数内部声明 var that = this 呢

    看一个例子 $('#conten').click(function(){ //this是被点击的#conten var that =this; $('.conten').each(function() ...

  8. 【SAM】bzoj5084: hashit

    做得心 力 憔 悴 Description 你有一个字符串S,一开始为空串,要求支持两种操作 在S后面加入字母C 删除S最后一个字母 问每次操作后S有多少个两两不同的连续子串 Input 一行一个字符 ...

  9. centos7无法切换startx

    centos光盘安装后,显示命令行模式,通过startx无法进入图形界面? 解决方法:1.使用yum grouplist查看,根据显示的结果采用不同的界面格式,我用的是 yum groupinstal ...

  10. IAR生成bin,HEX文件

    1.生成bin,hex文件 options->output converter->output format binary:.bin文件:intel extended:hex文件. 生成的 ...