3. 写代码

1. 不使用临时临边交换数据

void swap(int &a,int &b)
{
  a = a^b;
  b = a^b;
  a = a^b;
}
//一个数和0进行异或,仍然是自身。

2. 将特定位置1,将特定位置0

#define bit_set(n, value)     value | (1<<n)
#define bit_clear(n,value)   value&(~(1<<n))
  • 特定位,置1功能——将对应的位置1,并进行 或 操作
  • 特定位,清零功能——将对应的位置0,然后取反,并与待操作数进行 与 操作

3. 实现字符串的拷贝strcpy

char* strcpy(char* dest,const char* src)
{
    assert(src != NULL && dest != NULL);
    char* p1 = dest;
    char* p2 = src;
  
    #if 0
    while(p2){
        *p1++ = *p2++;
    }
    p1[strlen[p2]+1] = '\0';
    return p1;
    #else
    while((*p1++ = *p2++) != '\0');  //这种写法更好,效率更高
    return p1;
    #endif

}

注意事项

  1. const修饰源字符串
  2. 检查指针的有效
    • 最好不要使用assert(!p1 && !p2)
    • 也尽量不要使用assert(p1 != 0 && p2!= 0)
  3. 注意字符串结尾的 ‘\0’问题

4. 实现strlen 功能

注意的问题

  • 在c语言中,局部变量如果未初始化,其值是随机的。
    定义局部变量其实就是在栈中通过移动栈指针给程序提供一个内存空间和这个局部变量名绑定。因为栈内存是反复使用的,且栈内存比较脏,上次使用完没有清零。所以说使用栈来实现的局部变量定义时如果不显式初始化,值就是脏的。
  • 在c语言中,全局变量和静态变量都会自动初始化为0,堆和栈中的局部变量如果不初始化会有不可预测的值。
  • 在C++中,会执行 默认初始化,那什么是默认初始化?
    • 栈中的变量和堆中的变量会保有不确定的值。
    • 全局变量和静态变量会初始化为0。
      所以函数体中的变量定义是这样的规则:
  int i;             // 不确定值
  int i = int();      // 0
  int* p = new int;   // 不确定值
  int* p = new int(); // 0

#include <assert.h>
#include <stdio.h>
size_t strlen(const char* str)
{
    int n =0;
    char* p1 = str;
    assert(p1 != NULL);  
    while(p1 != '\0')
    {
      n++;
    }
    return n;
}

strlen 与 sizeof的区别

  • sizeof是运算符,strlen是库函数
  • sizeof可以用类型、变量做参数,strlen 只能用char* 做参数,且必须以 \0结尾。
  • 数组做sizeof的参数不退化,传递给strlen就退化为指针了
  • sizeof是在编译的时候计算所占内存大小,strlen是在运行的时候计算出来。

5. 实现strcat功能

实现原理

  • 首先将目的字符串移动到最后一位,及‘\0’的位置
  • 然后进行拷贝,需要注意末尾字符‘\0’的问题。
#include <assert.h>
#include <stdio.h>
char* strcat(char* str1,const char* str2)
{
    char* p1 = str1;
    char* p2 = str2;
    assert((p1 != NULL) && (p2 !=NULL)); 
    #if 0 // self
    int n = strlen(p1);
    while( *p1[n+1]++ = *p2++ ) != '\0');
    return p1;
    #else
    while(*p1++ != '\0');
    while((*p1++ = *p2++) != '\0');
    return p1;
    #endif
}

6. 字符串比较函数

规则

  • 若s1 == s2,返回零
  • 若s1 > s2,返回正数
  • 若s1 < s2,返回负数
int strcmp(const char* s1,const char* s2)
{
    char* p1 = s1;
    char* p2 = s2;
    assert( (p1 != NULL)&&(p2 != NULL)  );
    while(*p1 == *p2)
    {
        if(*p1 == '\0' )
          return 0;
        ++p1;
        ++p2;
    }
    return *p1 - *p2;
}

注意:关于assert的说明
assert是宏,不是函数,原型定义在头文件 assert.h中:

  void assert(int expression);

宏assert经常用于在函数开始处检验传入参数的合法性,可以将其看做异常处理的一种高级形式。
assert的作用是先计算表达式expression,然后判断

  • 如果表达式值为假,那么先向stderr打印错误信息,然后通过调用abort来终止程序运行
  • 如果表达式值为真,继续运行后面的程序。

7. 实现memmove

void* memmove(void* dst, const void* src,size_t n)
{
    char* p1 = (char*)dst;
    char* p2 = (char*)src;
    assert( (p1 != NULL)&&(P2 != NULL));
    
    #if 0  //self
    // 需要考虑内存重叠问题
    p2+=n-1;
    p1+=n-1;
    while(n--)
    {
        *p1-- = *p2--
    }
    return p1;
    #else
    if((&p1 -&p2)<n)
    {
        p2+=n-1;
        p1+=n-1;
        while(n--)
        {
            //*p1-- = *p2--
            *--p1 = *--p2;
        }
    }else{
        while(n--){
          *p1++ = *p2++;
        }
    }
    #endif
}

8.实现strtok功能

char* strtok(char* str, const char* delim ){
    assert( delim != NULL);

    const char*  left = NULL
    if(str == NULL)
      str = left;
    if(str == NULL)
        return NULL;
    
    const char* p;
    bool flag;
    while(*str != 0){
        p = delim;
        flag = false;
        while(*p != 0){
            if(*p++ == *str)
            {
                flag = ture;
                break;
            }
        }
        if(!flag) // 这里不能理解
            break;
        ++str;
    }

    char* s = str;
    while(*s != 0)
    {
        p = delim;
        flag = false;
        while( *p != 0)
        {
            if(*p++ = *s)
            {
                flag = true;
                *s = 0;
                break;
            }
        }
        ++s;
        if(flag )
        {
            left = s;
            return str;
        }
    }
    left = NULL;
    return left;
}

9.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容

  • __block和__weak修饰符的区别其实是挺明显的:1.__block不管是ARC还是MRC模式下都可以使用,...
    LZM轮回阅读 3,327评论 0 6
  • 史上最全的iOS面试题及答案 iOS面试小贴士———————————————回答好下面的足够了----------...
    Style_伟阅读 2,359评论 0 35
  • 最全的iOS面试题及答案 iOS面试小贴士 ———————————————回答好下面的足够了-----------...
    zweic阅读 2,703评论 0 73
  • 随着道天碑轰然的塌落,整个观剑台上众人也是发出一阵惊呼,天哪?这届什么情况?凡台论剑开始,顶级的泛古神兵,准泛古神...
    寒风冷夜冻屁屁阅读 398评论 0 2
  • 读书笔记 三月五日 星二 《左传》 “多行不义必自毙”出自《左传·隐公·郑伯克段于鄢》。原义为多做不...
    戴旭辉阅读 239评论 0 2