实现my_strcpy函数

题目描述:

写出完整版的strcpy函数

代码1:

char * my_strcpy(char *str1,const char *str2)   //[1]
{
    assert(str1 != NULL && str2 != NULL);    //[2]

    char *ret = str1;  //[3]

    while (*str2!='\0')//[4]
    {
    	*str1= *str2;
    	str1++;
    	str2++;
    }; 
    *(str1+1) = '\0';
    return ret;
}

分析1:

1.为什么用const修饰str2?
用const修饰原始字符串,防止原始字符串被修改。
2.为什么要有空指针检查?
不检查指针的有效性,说明答题者不注重代码的健壮性。
3.为什么返回值要返回目标地址并且返回值类型要为char*?
返回char*类型可以使函数支持链式表达式,例如:int i = strlen(strcpy(str1,str2));又如,char * str1=strcpy(new char[10],str2);返回str2的原始值是错误的。其一,源字符串肯定是已知的,返回它没有意义。其二,不能支持形如第二例的表达式。其三,把const char *作为char *返回,类型不符,编译报错。
4.如果str1,str2内存重叠,怎么办?
如果str1,str2内存发生重叠,例如strcpy(str1+1,str1),我们赋值会在赋值时将str1中的字符进行修改,并且将str1的’\0’覆盖掉,while循环就无法正常退出。所以我们还需要考虑到内存重叠的情况下怎么处理。

完整的正确代码:

char * my_strcpy(char *dst,const char *src)
{
    assert(dst != NULL && src != NULL);

    char *ret = dst;

    my_memcpy(dst, src, strlen(src)+1);

    return ret;
}

char *my_memcpy(char *dst, const char* src, int cnt)
{
    assert(dst != NULL && src != NULL);

    char *ret = dst; 

    if (dst >= src && dst <= src+cnt-1) //dst地址高于src地址并且有重复部分,从高地址开始复制
    {
        dst = dst+cnt-1;
        src = src+cnt-1;
        while (cnt--)
            *dst-- = *src--;
    }
    else    //正常情况或者dst地址低于src地址,从低地址开始复制
    {
        while (cnt--)
            *dst++ = *src++;
    }
    
    return ret;
}

主函数调用:

int main
{
	char str1[100] = "hello";
	char str2[100] = "hello,world";
	char str3[100] = "";
	char *str4 = my_strcpy(str1+1,str1);
	char *str5 = my_strcpy(str3,str2);
	cout<<"str1=>"<<str1<<endl;
	cout<<"str4=>"<<str4<<endl;
	cout<<"str5=>"<<str5;
	return 0;
}

调用结果:

在这里插入图片描述

分析2:

1.str1的内存地址高于str2的内存地址,我们就要从高地址开始赋值,这样我们才能得到我们需要的字符串
2.str1的内存地址小于str2的内存地址或者正常情况下,我们就直接从低地址开始赋值便可。
3.为什么my_strcpy函数的第二个参数为const char*类型,结果函数执行后str1的值被修改两者之间不冲突?

const char* 类型,定义一个指向字符常量的指针,这里,ptr是一个指向 char* 类型的常量,所以不能用ptr直接或者间接来修改所指向的内容,换句话说,*ptr的值为const,不能修改。但是ptr的声明并不意味着它指向的值实际上就是一个常量,而只是意味着对ptr而言,这个值是常量。实验如下:ptr指向str,而str不是const,可以直接通过str变量来修改str的值,但是确不能通过ptr指针来修改,实验如下:

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
减少库的使用,解决那些需要小代码量,但苦恼于没有简易的字符串处理函数的郁闷 char *itoa_private(int val, char *buf, unsigned radix);//整数转字符串 int my_isdigit(int ch);//判断字符是否为数字 long long StrToInt(const char *s,int sign);//字符串转数字 int atoi_32(const char *s);//将字符串str转换为32位整型,其正数的最值为0x7FFFFFFF,负数的最小值为0x80000000,考虑数字会溢出的情况 void LettersChange(unsigned char*str, unsigned char font);//大小写字母变成大小写字母 signed int st_strlen(unsigned char* str);//获取字符串长度 signed int st_strcmp(unsigned char *s,unsigned char *t);//比较两个字符串大小 unsigned char *st_strcpy(unsigned char *t,unsigned char *s);//字符串拷贝 signed int st_strncmp(unsigned char *dest,unsigned char *src,unsigned int Len);//可变长度字符串大小比较 signed char st_toupper(unsigned char c);//小写字符转化为大写字符 unsigned char *st_strcat(unsigned char *s,unsigned char *t);//字符串连接 signed int st_memcpy(unsigned char *dest, unsigned char *src, unsigned int Len);//可变长度内存拷贝 signed int st_memset(unsigned char *dest,unsigned char byte, unsigned int Len);//设置长度为Len的内存块为byte signed int st_memcmp(unsigned char* dest, unsigned char* src, unsigned int Len);//内存段内数据比较 int gsmInvertNumbers(const char* pSrc, char* pDst, int nSrcLength);//正常顺序的字符串转换为两两颠倒的字符串,若长度为奇数,补'F'凑成偶数 int gsmSerializeNumbers(const char* pSrc, char* pDst, int nSrcLength);//两两颠倒的字符串转换为正常顺序的字符串 int gsmEncode7bit(const char* pSrc, unsigned char* pDst, int nSrcLength);//7bit编码 int gsmDecode7bit(const unsigned char* pSrc, char* pDst, int nSrcLength);//7bit解码 int gsmString2Bytes(const char* pSrc, unsigned char* pDst, int nSrcLength);//可打印字符串转换为字节数据 int gsmBytes2String(const unsigned char* pSrc, char* pDst, int nSrcLength);//字节数据转换为可打印字符串
基于DOS的多任务系统的实现 #include<stdio.h> #include<stdlib.h> #include <time.h> #include<dos.h> /*定义TCB状态*/ #define FINISHED 0 #define RUNNING 1 #define READY 2 #define BLOCKED 3 #define NTCB 5 /*定义最大空闲TCB个数*/ #define TC 2 /*定义时间片长度*/ #define NBUF 6 /*定义缓冲区大小*/ #define GET_INDOS 0x34 #define GET_CRIT_ERR 0x5d06 struct TCB{ unsigned char *stack; /*线程堆栈起始地址*/ unsigned ss; /*堆栈段址*/ unsigned sp; /*堆栈指针*/ char state; /*线程状态*/ char name[15]; /*线程外部标识符*/ struct TCB *next; }tcb[NTCB]; /*初始化堆栈时使用*/ struct int_regs{ unsigned bp, di, si, ds, es, dx, cx, bx, ax, ip, cs, flags, off, seg; }; char fpub[3]; int current= -1; /*定义一个当前TCB下标的全局变量*/ int timecount = 0; /*定义时间片*/ char far *indos_ptr = 0; /*该指针变量存放INDOS表示的地址*/ char far *crit_err_ptr = 0; /*该指针变量存放严重错误标志的地址*/ void interrupt (*old_int8)(void);/*旧的时钟中断处理程序*/ typedef int (far *codeptr)(void); /*定义了一个函数指针类型*/ int buffer[NBUF] = {-1,-1,-1,-1,-1,-1}; /*生产者消费者中的缓冲区*/ int in = 0; int out = 0; typedef struct{ int value; struct TCB *wq; }semaphore; semaphore mutex={1,NULL},empty={NBUF,NULL},full={0,NULL},Mutex2={1,NULL}; /*生产者消费者中的信号量*/ void InitDos(void) { union REGS regs; struct SREGS segregs; regs.h.ah = GET_INDOS; intdosx(&regs,&regs,&segregs); indos_ptr = MK_FP(segregs.es,regs.x.bx); if(_osmajor<3) crit_err_ptr = indos_ptr+1; else if(_osmajor==3 && _osminor==0) crit_err_ptr = indos_ptr-1; else{ regs.x.ax = GET_CRIT_ERR; intdosx(&regs,&regs,&segregs); crit_err_ptr = MK_FP(segregs.ds,regs.x.si); } } int DosBusy(void) { if(indos_ptr && crit_err_ptr) return (*indos_ptr || *crit_err_ptr); else return -1; } int finished(void) { int i; for(i=1; i<NTCB; i++) if(tcb[i].state != FINISHED) return 0; return 1; } int Seeknext() { int i,ks; i=current+1; ks=0; disable(); while(ks<NTCB) { if(tcb[i].state==READY) { return i; } i++; ks++; i=i%NTCB; } printf("Seeknext tcb is error!!\n"); enable(); } void interrupt my_swtch(void) { disable();/*开中断*/ /*保护正在执行的线程current的现场,暂停它的执行*/ tcb[current].ss=_SS; tcb[current].sp=_SP; if(tcb[current].state==RUNNING) tcb[current].state=READY; /*找到新的就绪线程i*/ current=Seeknext(); tcb[current].state=RUNNING; /*切换堆栈,恢复线程i的现场,把CPU分派给它*/ _SS=tcb[current].ss; _SP=tcb[current].sp; /*重新开始计时*/ timecount=0; enable();/*关中断*/ } void interrupt new_int8(void) { /*调用原来的时钟中断服务程序*/ (*old_int8)(); /*进行计时*/ timecount++; /*当前线程的时间片到否*/ if(timecount >= TC) if(!DosBusy()) { /*调用my_swtch进行重新调度*/ my_swtch(); } } void Destroy(int i) { if(tcb[i].state==RUNNING) { disable(); tcb[i].state=FINISHED; free(tcb[i].stack); enable(); } return; } void over(void) { Destroy(current); printf("%s is finished!\n", tcb[current].name); my_swtch(); } void tcb_state() { int i; printf("These are the information of all threads: \n"); for(i=0;i<NTCB-1;i++) { printf("the key word of the thread is : %d\n the name of thread is : %s\n the state of the thread is ",i,tcb[i].name); switch(tcb[i].state) { case (1): printf("Running \n");break; case (2): printf("Ready \n");break; case (3): printf("Blocked\n");break; case (0): printf("Finished\n");break; } } } /*创建线程*/ int create(char *name, codeptr code, int stacklen) { int i = 0; struct int_regs *temp; while(tcb[i].state != FINISHED) /*查找空闲TCB块*/ i++; if(i == NTCB) return -1; /*没有空闲TCB块可用*/ strcpy(tcb[i].name, name); tcb[i].state = READY; tcb[i].stack = (unsigned char*)malloc(stacklen); /*为新线程分配私有堆栈空间*/ tcb[i].stack = tcb[i].stack + stacklen; /*初始化新线程的私有堆栈*/ temp = (struct int_regs *)tcb[i].stack-1; temp->ds = _DS; temp->es = _ES; temp->flags = 0x200; temp->ip = FP_OFF(code); temp->cs = FP_SEG(code); temp->off = FP_OFF(over); /*将over函数压入堆栈,线程结束自动执行*/ temp->seg = FP_SEG(over); tcb[i].ss = FP_SEG(temp); tcb[i].sp = FP_OFF(temp); return i; } void block(semaphore *sem) { struct TCB *p; disable(); tcb[current].state = BLOCKED; p = sem->wq; if(p == NULL){ sem->wq = &tcb[current]; } else{ while(p->next != NULL) p = p->next ; p->next = &tcb[current]; } tcb[current].next = NULL; my_swtch(); enable(); } void wakeup(semaphore *sem) { struct TCB *p; disable(); p = sem->wq; if(p != NULL){ p->state = READY; sem->wq = sem->wq->next; } enable(); } void wait(semaphore *sem) { disable(); sem->value = sem->value - 1; if(sem->value < 0) { printf("\nthe thread of %s is blocked\n",tcb[current].name); block(sem); } enable(); } void signal(semaphore *sem) { disable(); sem->value = sem->value + 1; if(sem->value <= 0) wakeup(sem); enable(); } void proceducer() { int i, j, k; for(i = 1; i <=13;i++){ wait(&empty); wait(&mutex); buffer[in] = i*i; printf("%s puts a number of %d in the buffer \n",tcb[current].name, buffer[in]); /*for(j=0; j<10000; j++) for(k=0; k<10000; k++);*/ in = (in +1) % NBUF; signal(&mutex); signal(&full); } } void consumer() { int i, j, k; for(i = 1; i<=7;i++){ wait(&full); wait(&mutex); printf("consumer gets the number of %d from the buffer\n", buffer[out]); buffer[out] = -1; /*for(j=0; j<1000; j++) for(k=0; k<10000; k++);*/ out = (out+1) % NBUF; signal(&mutex); signal(&empty); } } void f1() { int i,j,k; wait(&Mutex2); strcpy(fpub,"f1"); signal(&Mutex2); for(i=1;i<=22;i++) { wait(&Mutex2); printf("%s is running !\n",fpub); signal(&Mutex2); for(j=0;j<10000;j++) for(k=0;k<10000;k++); } } void f2() { int i,j,k; wait(&Mutex2); /*做放入数的操作*/ strcpy(fpub,"f2"); signal(&Mutex2); for(i=1;i<=33;i++) { wait(&Mutex2); printf("%s is running !\n",fpub); signal(&Mutex2); for(j=0;j<10000;j++) for(k=0;k<10000;k++); } } void InitTcb()/*TCB的初始化*/ { int i; for(i=0;i<NTCB;i++) { tcb[i].state=FINISHED; tcb[i].name[0]='\0'; tcb[i].next=NULL; } } int main(void) { InitDos(); InitTcb(); old_int8 = getvect(8); strcpy(tcb[0].name, "main"); tcb[0].state = RUNNING; current = 0 ; create("proceducerOne", (codeptr)proceducer, 1024); create("consumer", (codeptr)consumer, 1024); /*create("proceducerTwo", (codeptr)proceducer, 1024); create("f1",(codeptr)f1,1024); create("f2",(codeptr)f2,1024);*/ tcb_state(NTCB); setvect(8, new_int8); my_swtch(); while(!finished()) ; strcpy(tcb[0].name, "\0"); tcb[0].state = FINISHED; setvect(8, old_int8); printf("\n"); tcb_state(NTCB); printf("\nMulti_task system terminated.\n"); getchar(); return 0; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值