zoukankan      html  css  js  c++  java
  • C语言中strcpy(char *strDest, const char *strScr)字符串复制库函数的理解与分析

    1.原版的strcpy()函数原型

    char * strcpy( char *strDest, const char *strSrc )
    {
     assert( (strDest != NULL) && (strSrc != NULL) );
     char *address = strDest;
     while( (*strDest++ = * strSrc++) != ‘’ );
     return address;
    }

    在库函数中,字符的赋值所采用的循环代码,只用了一行代码:while( (*strDest++ = * strSrc++) != ‘’ );。It is so beautiful !

    2.有哪些问题

      从source 往dest里赋值时,如果dest的长度大于source 的长度,会发生什么情况呢。

      可是有时候我们会不小心把*strScr的长度大于*strDest的长度了 这时会有什么效果呢
    就比如:

     char str_dest[10];
     char str_scr[20];
     strcpy(str_dest, str_scr);
    

    有位大哥做了验证:程序并不会报错,它会继续输出str_scr中的内容;而我的解释是,这是系统依赖的错误

    举个简单的例子:

      # include <stdio.h>
      # include <string.h>
      int main()
      {
          char str1[3];
          char str2[20]={"this is a test"};
          strcpy(str1, str2);
          printf("%s
    ", str1);
          return 0;
      }

     运行结果:

      this is a test
      这时我们会把目光注视到原函数上,我们发现strcpy的原函数并没有加两个字符串长度的限制条件,它只是把原字符串中的内容一个一个地赋值到目标字符串中,而且到最后还给目标字符串加上了结束符“”。那么如果目标字符串长度不够时会怎么样呢大哥认为:

      它会继续一个一个地赋值字符。拿上面的例子 str1[3], str2[20]="this is a test", str2往str1里赋值。当str2里的thi 到s 的时候,str1的长度不够了,但是数字中的地址是连续的,比如str1的首地址是1000,那么str1[0]=1000,str1[1]=1001,str1[2]=1002, 这个时候还要继续往str1里赋值,怎么办,地址还会继续增加的,那么继续增加的地址是我们没有申请的空间的,这样的话就会很危险的,如果没有申请的地址空间没有被系统占用还好,如果被系统占用的话系统可能就会崩溃的,所以在使用strcpy函数时要小心谨慎, 原字符串长度要小于目标字符串的长度。

    3.ANSI C 中strcpy 的安全版本: strncpy

      在 ANSI C 中,strcpy 的安全版本是 strncpy

    char *strncpy(char *s1, const char *s2, size_t n);

    但 strncpy 其行为是很诡异的(不符合我们的通常习惯)。标准规定 n 并不是 sizeof(s1),而是要复制的 char 的个数。一个最常见的问题,就是 strncpy 并不帮你保证 ''结束。

    char buf[8];
    strncpy( buf, "abcdefgh", 8 );

    看这个程序,buf 将会被 "abcdefgh" 填满,但却没有  ''结束符了。

      

      另外,如果 s2 的内容比较少,而 n 又比较大的话,strncpy 将会把之间的空间都用 '' 填充。这又出现了一个效率上的问题,如下:

    char buf[80];
    strncpy( buf, "abcdefgh", 79 );

    上面的 strncpy 会填写 79 个 char,而不仅仅是 "abcdefgh" 本身。

    strncpy 的标准用法为:(手工写上 '' )

    strncpy(path, src, sizeof(path) - 1);
    path[sizeof(path) - 1] = '/0';
    len = strlen(path);
    

    4.有关strcpy的面试题参考 这里 :

      很多公司的面试官在面试程序员的时候,要求应聘者写出库函数strcpy()的工作方式或者叫实现,很多人以为这个题目很简单,实则不然,别看这么一个小小的函数,他可以从三个方面来考查:

    (1)编程风格
    (2)出错处理
    (3)算法复杂度分析(用于提高性能)


    如果这个题目10分的话,我们列出2分到10分的答案
     

    2分

    void strcpy( char *strDest, char *strSrc )
    {
      while( (*strDest++ = * strSrc++) != ‘’ );
    }
    

      

    4分

    void strcpy( char *strDest, const char *strSrc )
    //将源字符串加const,表明其为输入参数,加2分
    {
      while( (*strDest++ = * strSrc++) != ‘’ );
    }
    

      

    7分

    void strcpy(char *strDest, const char *strSrc)
    {
     //对源地址和目的地址加非0断言,加3分
     assert( (strDest != NULL) && (strSrc != NULL) );
     while( (*strDest++ = * strSrc++) != ‘’ );
    }
    

      

    10分

    //为了实现链式操作,将目的地址返回,加3分!
    char * strcpy( char *strDest, const char *strSrc )
    {
     assert( (strDest != NULL) && (strSrc != NULL) );
     char *address = strDest;
     while( (*strDest++ = * strSrc++) != ‘’ )
    NULL;
      return address;//引用返回地址,方便链式操作!!
    }
    

      从2分到10分的几个答案我们可以清楚的看到,小小的strcpy竟然暗藏着这么多玄机,真不是盖的!需要多么扎实的基本功才能写一个完美的strcpy啊!

    看了不同分值的strcpy版本,应该也可以写出一个10分的strlen函数了,
    完美的版本为:

    int strlen( const char *str ) //输入参数const
    
    {
     assert( strt != NULL ); //断言字符串地址非0
     int len;
     while( (*str++) != '' )
     {
      len++;
     }
     return len;
    }
    

      

     

  • 相关阅读:
    妙味——字符串方法2
    妙味——字符串方法
    [LeetCode][JavaScript]Shortest Palindrome
    [LeetCode]Kth Largest Element in an Array
    [LeetCode][JavaScript]Word Ladder
    [LeetCode][SQL]Second Highest Salary
    [LeetCode][JavaScript]Clone Graph
    [LeetCode][JavaScript]Merge k Sorted Lists
    [LeetCode][JavaScript]Merge Two Sorted Lists
    [LeetCode][JavaScript]Valid Sudoku
  • 原文地址:https://www.cnblogs.com/haore147/p/3646311.html
Copyright © 2011-2022 走看看