C中atoi和strcpy的自定义实现

  这是两道经常考到的笔试题,看似简单的实现,其实专注到细节,还是有很多需要注意扣分的地方。

atoi实现:

 1 #include <iostream>
 2 #include<ctype.h>
 3 using namespace std;
 4
 5 typedef enum status{
 6     OK,ERROR
 7 }Status;
 8
 9 Status myErrno = ERROR;
10 int my_atoi(const char *p);
11 int main()
12 {
13     char *mystr = "45678910";
14     int ret = my_atoi(mystr);
15     cout << ret << endl;
16     return 0;
17 }
18
19 //实现atoi函数,将字符串转换为数字
20 int my_atoi(const char *p){
21     myErrno = ERROR;
22     if(NULL == p)
23         return 0;
24
25     int ret = 0;
26
27     const char *temp = p;
28
29     //判断如果是前几位为空格,则向前移动字符串位置
30     while(isspace(*temp))
31         temp++;
32
33     //判断符号位,是否为负数
34     bool minus = *temp==‘-‘ ? true : false;
35
36     //有符号位
37     if(‘+‘ == *temp || ‘-‘ == *temp)
38         ++temp;
39
40     while(*temp != ‘\0‘){
41         if(isdigit(*temp)){ //是数字情况下
42             if((!minus && ret > 0x7FFFFFFF) || (minus && -minus < 0x80000000)){
43                 //若当前数值范围超出int所能表达的范围
44                 myErrno = ERROR;
45                 return 0;
46             }
47
48             ret = ret*10 + (*temp++ - ‘0‘);
49         }else{
50             //某位不是数字
51             myErrno = ERROR;
52             return 0;
53         }
54
55     }
56
57     if(*temp == ‘\0‘){
58         myErrno = OK;
59     }
60
61     return minus ? -ret : ret;
62 }

strcpy的实现:

1 //实现trcpy函数
2 char *my_strcpy(char *dest,const char *src){
3     assert(dest != NULL && src != NULL);
4
5     char *ret = dest;
6     while((*dest++ = *src++) != ‘\0‘);
7
8     return ret;
9 }

  对于strcpy的实现,还是会有问题的,需要考虑到内存重叠的情况,比如:

  char *str = ‘abcde‘;

  strcpy(str,str+1);  //结果为bcde

  strcpy(str+1,str);  //期望结果:aabcde,但运行会报错,因为str内存有重叠,会把‘\0‘覆盖掉

  但是如果调用系统中的strcpy是不会有这个问题,其实要解决这个问题需要配合memcpy来使用  

1 char *my_strcpy(char *dest,const char *src){
2     assert(dest != NULL && src != NULL);
3
4     char *ret = dest;
5     memcpy(dst,src,strlen(src)+1);
6
7     return ret;
8 }

  至于memcpy的实现,建议参考 http://blog.csdn.net/gpengtao 这为大牛的实现:

 1 void * my_memcpy(void *dst,const void *src,unsigned int count)
 2 {
 3      assert(dst);
 4      assert(src);
 5      void * ret = dst;
 6      if (dst <= src || (char *)dst >= ((char *)src + count))//源地址和目的地址不重叠,低字节向高字节拷贝
 7      {
 8          while(count--)
 9          {
10              *(char *)dst = *(char *)src;
11              dst = (char *)dst + 1;
12              src = (char *)src + 1;
13          }
14      }
15      else                        //源地址和目的地址重叠,高字节向低字节拷贝
16      {
17          dst = (char *)dst + count - 1;
18          src = (char *)src + count - 1;
19          while(count--)
20          {
21              *(char *)dst = *(char *)src;
22              dst = (char *)dst - 1;
23              src = (char *)src - 1;
24          }
25     }
26     return ret;
27 }
时间: 2024-11-22 20:27:14

C中atoi和strcpy的自定义实现的相关文章

转载 C++常用库函数atoi,itoa,strcpy,strcmp的实现

C++常用库函数atoi,itoa,strcpy,strcmp的实现 C语言字符串操作函数 1. 字符串反转 - strRev2. 字符串复制 - strcpy3. 字符串转化为整数 - atoi4. 字符串求长 - strlen5. 字符串连接 - strcat6. 字符串比较 - strcmp7. 计算字符串中的元音字符个数8. 判断一个字符串是否是回文1. 写一个函数实现字符串反转 版本1 - while版 void strRev(char *s){    char temp, *end 

Sqlserver中存储过程,触发器,自定义函数(一)

Sqlserver中存储过程,触发器,自定义函数 1.存储过程有关内容存储过程的定义:存储过程的分类:存储过程的创建,修改,执行:存储过程中参数的传递,返回与接收:存储过程的返回值:存储过程使用游标. 1.1存储过程的定义:存放在服务器上预先编译好的sql语句,可以给存储过程传递参数,也可以从存储过程返回值. 优点:提供了安全访问机制,比如可以将不同的存储过程的执行权限赋予权限不同的用户:改进了执行性能,因为存储过程是预编译的:减少了网络流量,因为在调用存储过程时,传递的字符串很短,没有很长的s

Sqlserver中存储过程,触发器,自定义函数(二)

Sqlserver中存储过程,触发器,自定义函数: 自定义函数:1.函数类型:2.函数的参数和返回值: 1.函数类型:标量值函数,返回的是一个标量值表值函数:内联表值函数:多语句表值函数. 标量值函数: 1 go 2 create function SumOrders(@职工号 varchar(20))--指定参数名,和返回类型 stuNo 3 returns int --指定返回类型 4 begin 5 declare @订单总数 int --学生人数sumstudent 6 select @

Sqlserver中存储过程,触发器,自定义函数

Sqlserver中存储过程,触发器,自定义函数: 1. 触发器:是针对数据库表或数据库的特殊存储过程,在某些行为发生的时候就会被激活 触发器的分类: DML触发器:发生在数据操作语言执行时触发执行的存储过程,Insert,Update,Delete After触发器:记录被改变之后激活执行 Instead of触发器:记录被改变之前激活执行. DDL触发器:响应数据定义语言执行时触发执行的存储过程,一般用于执行数据库中的管理任务 审核和规范数据库的操作: 防止数据表结构被更改或删除 2. ht

FastReport调用Delphi中的人民币大写转换自定义函数

FastReport调用Delphi中的人民币大写转换自定义函数 FastReport调用Delphi中的人民币大写转换自定义函数 function TJzpzEdit1.MoneyCn(mmje: Double): string; const s1: string = '零壹贰叁肆伍陆柒捌玖'; s2: string = '分角元拾佰仟万拾佰仟亿拾佰仟万'; function StrTran(const S, s1, s2: string): string; begin Result := S

LinQ 泛型方法Array&gt;ForEach在数组中进行迭代并调用自定义的委托

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.IO; namespace LambdaExpressionAction { class Program { static void Main(string[] args) { //定义输出委托 Action<double> print = amo

Linq to Sql:N层应用中的查询(上) : 返回自定义实体

原文:Linq to Sql:N层应用中的查询(上) : 返回自定义实体 如果允许在UI层直接访问Linq to Sql的DataContext,可以省去很多问题,譬如在处理多表join的时候,我们使用var来定义L2S查询,让IDE自动推断变量的具体类型(IQueryable<匿名类型>),并提供友好的智能提示:而且可以充分应用L2S的延迟加载特性,来进行动态查询.但如果我们希望将业务逻辑放在一个独立的层中(譬如封装在远程的WCF应用中),又希望在逻辑层应用Linq to sql,则情况就比

HashSet存储过程中如何排除不同的自定义对象?

HashSet HashSet存储过程中如何排除不同的自定义对象? 先看一个小demo public class Demo1 { public static void main(String[] args) { //Person4类是一个失血模型,它有姓名和年龄两个属性 HashSet<Person4> set = new HashSet<>(); set.add(new Person4("张三", 23)); set.add(new Person4("

润乾报表设计器中使用 spring 框架实现自定义数据集

spring是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.在 web 开发环境中经常会与 struts.hibernate联合起来使用,进行规范的框架结构开发.润乾中的二次开发也可以与 SSH 框架相结合部署到 web 项目中.本文介绍在设计时没有启动 web 服务,在设计器中使用 spring 的方式来实现自定义数据集. 实现思路:编写两个自定义数据集,一个在设计器中使用,一个在 web 项目中使用,在设计器中使用的类需要编写临时加载 spring 框架配置文件的代码,启动 spr