zoukankan      html  css  js  c++  java
  • strcpy/strlen/strcat/strcmp面试总结

    《strcpy拷贝越界问题》

    一. 程序一

    
    

    #include<stdio.h>  
    #include<string.h>  
    void main()  
    {  
     char s[]="123456789";  
     char d[]="123";  
     strcpy(d,s);  
     printf("d=%s,
    s=%s",d,s);  
    } 
    执行结果:

    解释:

    首先要解释一下,char s[]="123456789"; char d[]="123"; 这样定义的数组和变量存放在栈内存中。
    栈内存是一个自顶向下分布的数据结构,那么越先定义的变量地址就越高,越后定义的地址就越低。
    s比d定义在前,那么s得到了高地址,而d得到了相对低的地址,那么内存中的存放形式就是
    d[] <- | -> s[]
    '1' '2' '3' '' | '1' '2' '3' '4' '5' '6' '7' '8' '9' ''
    字符串拷贝后:
    '1' '2' '3' '4 ' | '5' '6' '7' '8' '9' '' '7' '8' '9' ''
    中间的‘|’表示s[]的起始位置。
    所以此时输出的是d的值是 '1' '2' '3' '4' '5' '6' '7' '8' '9' '',s的值是 '5' '6' '7' '8' '9' ''

    二. 程序二

    
    

    #include<stdio.h>  
    #include<string.h>  
    void main()  
    {  
      char d[]="123";  
     
     char s[]="123456789";  
     strcpy(d,s);  
     printf("d=%s,
    s=%s",d,s);  
    }  
    运行结果:

    说明:

    虽然可以看到正确的输出结果d=123456789,s=123456789执,但是产生运行错误!

    这是因为字符串拷贝后,越过了目标字串的实际空间,访问到了不可预知的地址了。

    三. 字符串操作函数原型

    
    
    一、字符串拷贝strcpy

    函数strcpy的原型是char* strcpy(char* des , const char* src),des 和 src 所指内存区域不可以重叠且 des 必须有足够的空间来容纳 src 的字符串。

    #include <assert.h>
    #include <stdio.h>
    
    char* strcpy(char* des, const char* src)
    {
    	assert((des!=NULL) && (src!=NULL)); 
    	char *address = des;  
    	while((*des++ = *src++) != '')  
    		;  
    	return address;
    }

    要知道 strcpy 会拷贝’’,还有要注意:

    • 源指针所指的字符串内容是不能修改的,因此应该声明为 const 类型。

    • 要判断源指针和目的指针为空的情况,思维要严谨,这里使用assert(见文末)。

    • 要用一个临时变量保存目的串的首地址,最后返回这个首地址。

    • 函数返回 char* 的目的是为了支持链式表达式,即strcpy可以作为其他函数的实参。

    二、字符串长度strlen

    函数strlen的原型是size_t strlen(const char *s),其中 size_t 就是 unsigned int。

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

    strlen 与 sizeof 的区别:

    • sizeof是运算符,strlen是库函数。

    • sizeof可以用类型、变量做参数,而strlen只能用 char* 变量做参数,且必须以结尾。

    • sizeof是在编译的时候计算类型或变量所占内存的大小,而strlen的结果要在运行的时候才能计算出来,用来计算字符串的长度。

    • 数组做sizeof的参数不退化,传递给strlen就退化为指针了。

    三、字符串连接strcat

    函数strcat的原型是char* strcat(char* des, char* src),des 和 src 所指内存区域不可以重叠且 des 必须有足够的空间来容纳 src 的字符串。

    #include <assert.h>
    #include <stdio.h>
    
    char* strcat(char* des, const char* src)   // const表明为输入参数 
    {  
    	assert((des!=NULL) && (src!=NULL));
    	char* address = des;
    	while(*des != '')  // 移动到字符串末尾
    		++des;
    	while(*des++ = *src++)
    		;
    	return address;
    }
    四、字符串比较strcmp

    函数strcmp的原型是int strcmp(const char *s1,const char *s2)

    • 若s1==s2,返回零;
    • 若s1>s2,返回正数;
    • 若s1<s2,返回负数。

    即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇为止。

    #include <assert.h>
    #include <stdio.h>
    
    int strcmp(const char *s1,const char *s2)
    {
    	assert((s1!=NULL) && (s2!=NULL));
        while(*s1 == *s2)
        {
            if(*s1 == '')
                return 0;
             
            ++s1;
            ++s2;
        }
        return *s1 - *s2;
    }
    附:
    一.assert()断言

    assert是宏,而不是函数。它的原型定义在头文件 assert.h 中:

    1
    void assert( int expression );

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

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

    • 如果表达式值为真,继续运行后面的程序。

    注意:assert只在 DEBUG 下生效,在调试结束后,可以通过在#include <assert.h>语句之前插入#define NDEBUG来禁用assert调用。

    二.函数面试时操作得分点总结

    //得2分 
    void strcpy( char *dest, char *src ) 
    { 
        while( (*dest++ = * src++) != '' ); 
    } 
      
    //得4分 
    void strcpy( char *dest, const char *src ) 
    { 
        //将源字符串加const,表明其为输入参数,加2分 
        while( (*dest++ = * src++) != '' ); 
    } 
      
    //得7分 
    void strcpy(char *dest, const char *src) 
    { 
        //对源地址和目的地址加非0断言,加3分 
        assert( (dest != NULL) && (src != NULL) ); 
        while( (*dest++ = * src++) != '' ); 
    } 
      
    //得9分 
    //为了实现链式操作,将目的地址返回,加2分! 
    char * strcpy( char *dest, const char *src ) 
    { 
        assert( (dest != NULL) && (src != NULL) ); 
        char *tmp = dest; 
        while( (*dest++ = * src++) != '' ); 
        return tmp; 
    } 
      
    //得10分,基本上所有的情况,都考虑到了 
    //如果有考虑到源目所指区域有重叠的情况,加1分! 
    char * strcpy( char *dest, const char *src ) 
    { 
        if(dest == src) { return dest; } 
        assert( (dest != NULL) && (src != NULL) ); 
        char *tmp = dest; 
        while( (*dest++ = * src++) != '' ); 
        return tmp; 
    }
  • 相关阅读:
    Character Encoding题解(容斥)
    P1445 [Violet]樱花 题解(推式子)
    F. Stone 题解(对称博弈)
    M. 810975 题解(容斥)
    P1365 WJMZBMR打osu! / Easy 题解(期望dp)
    icpc济南
    C#创建windows服务并定时执行
    批处理 windows 服务的安装与卸载
    前台单击文件,jQuery删除后台相应真实的文件
    Jquery直接调用后台方法(WebMethod框架的使用)
  • 原文地址:https://www.cnblogs.com/hdk1993/p/4932419.html
Copyright © 2011-2022 走看看