美文网首页
2017C++面试题

2017C++面试题

作者: YBshone | 来源:发表于2017-04-09 22:57 被阅读0次
    1.sizeof和strlen的区别

    sizeof和strlen有以下区别:

    sizeof:操作符,编译时才计算出字符串占内存大小
    strlen:库函数,只在运行时才会计算数据类型的实际长度
    

     sizeof是一个操作符,strlen是库函数。  sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为‘\0‘的字符串作参数。  编译器在编译时就计算出了sizeof的结果。而strlen函数必须在运行时才能计算出来。并且sizeof 计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。  数组做sizeof的参数不退化,传递给strlen就退化为指针了。 注意:有些是操作符看起来像是函数,而有些函数名看起来又像操作符,这类容易混淆的名称一定要加以区分,否则遇到数组名这类特殊数据类型作参数时就很容易出错。最容易混淆为函数的操作符就是sizeof

    2.已知strcpy的函数原型:

    char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不调用C++/C 的字符串库函数,请编写函数 strcpy。

    /*
    编写strcpy函数(10分)
    已知strcpy函数的原型是
    char *strcpy(char *strDest, const char *strSrc);
    其中strDest是目的字符串,strSrc是源字符串。
    (1)不调用C++/C的字符串库函数,请编写函数 strcpy
    (2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
    答:为了 实现链式表达式。 // 2分
    例如 int length = strlen( strcpy( strDest, “hello world”) );
    */
    
    
    #include <assert.h>
    #include <stdio.h>
    char*strcpy(char*strDest, constchar*strSrc)
    {
    assert((strDest!=NULL) && (strSrc !=NULL)); // 2分
    char* address = strDest;   // 2分
    while( (*strDest++=*strSrc++) !='\0' )       // 2分
    NULL; 
    return address ;    // 2分
    }
    
    

    另外strlen函数如下:

    #include<stdio.h>
    #include<assert.h> 
    int strlen( constchar*str ) // 输入参数const
    {
    assert( str != NULL ); // 断言字符串地址非0
    int len = 0;
    while( (*str++) !='\0' ) 
    { 
    len++; 
    } 
    return len;
    }
    
    
    3.写一个“标准”宏 MIN

    #define min(a,b)((a)<=(b)?(a):(b))

    4已知String类定义如下:
    class String
    {
    public:
      String(const char *str = NULL); // 通用构造函数
      String(const String &another); // 拷贝构造函数
      ~String(); // 析构函数
      String& operater =(const String &rhs); // 赋值函数
    private:
      char* m_data; // 用于保存字符串
    };
    

    尝试写出类的成员函数实现。

    String::String(const char *str)
    {
    if ( str == NULL ) // strlen在参数为NULL时会抛异常才会有这步判断
    {
    m_data =newchar[1] ;
    m_data[0] ='\0' ;
    }
    else
    {
    m_data =newchar[strlen(str) +1];
    strcpy(m_data,str);
    }
    } 
    String::String(const String &another)
    {
    m_data =newchar[strlen(another.m_data) +1];
    strcpy(m_data,other.m_data);
    }
    
    String& String::operator=(const String &rhs)
    {
    if ( this==&rhs)
    return*this ;
    delete []m_data; //删除原来的数据,新开一块内存
    m_data =newchar[strlen(rhs.m_data) +1];
    strcpy(m_data,rhs.m_data);
    return*this ;
    }
    
    String::~String()
    {
    delete []m_data ;
    }
    

    5.malloc与new的区别

    1,malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
    2,对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
    3,因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
    4,C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。
    5.new可以认为是malloc加构造函数的执行。new出来的指针是直接带类型信息的。而malloc返回的都是void指针。

    6.QT版hello world

    #include <QApplication> 
    #include <QLabel> 
     
    int main(int argc, char *argv[]) 
    { 
            QApplication app(argc, argv); 
            QLabel *label = new QLabel("Hello, world!"); 
            label->show(); 
            return app.exec(); 
    }
    

    7.extern "C"的惯用法

    (1)在C++中引用C语言中的函数和变量,在包含C语言头文件(假设为cExample.h)时,需进行下列处理:

    extern"C"
    {
      #include"cExample.h"
    }
    

    而在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern"C"时会出现编译语法错误。

    C++引用C函数例子工程中包含的三个文件的源代码如下:

    /* c语言头文件:cExample.h */
    #ifndef C_EXAMPLE_H
    #define C_EXAMPLE_H
    externint add(int x, inty);
    #endif
    
    /* c语言实现文件:cExample.c */
    #include "cExample.h"
    int add( int x, int y )
    {
      return x + y;
    }
    

    8.[排序]文件中有一组整数,要求排序后输出到另一个文件中

    #include<iostream>
    #include<fstream>
    usingnamespace std;
    
    void Order(vector<int>& data)//bubble sort
    {
    int count = data.size() ;
    int tag =false ; // 设置是否需要继续冒泡的标志位
    for ( int i =0 ; i < count ; i++)
    {
    for ( int j =0 ; j < count - i -1 ; j++)
    {
    if ( data[j] > data[j+1])
    {
    tag =true ;
    int temp = data[j] ;
    data[j] = data[j+1] ;
    data[j+1] = temp ;
    }
    }
    if ( !tag )
    break ;
    }
    }
    
    void main( void )
    {
    vector<int>data;
    ifstream in("c:\\data.txt");
    if ( !in)
    {
    cout<<"file error!";
    exit(1);
    }
    int temp;
    while (!in.eof())
    {
    in>>temp;
    data.push_back(temp);
    }
    in.close(); //关闭输入文件流
    Order(data);
    ofstream out("c:\\result.txt");
    if ( !out)
    {
    cout<<"file error!";
    exit(1);
    }
    for ( i =0 ; i < data.size() ; i++)
    out<<data[i]<<"";
    out.close(); //关闭输出文件流
    }
    
    

    9.[链表]一个链表的结点结构

    struct Node
    {
    int data ;
    Node *next ;
    };
    typedef struct Node Node ;
    

    (1)已知链表的头结点head,写一个函数把这个链表逆序 ( Intel)

    Node * ReverseList(Node *head) //链表逆序
    {
    if ( head == NULL || head->next == NULL )
    return head;
    Node *p1 = head ;
    Node *p2 = p1->next ;
    Node *p3 = p2->next ;
    p1->next = NULL ;
    while ( p3 != NULL )
    {
    p2->next = p1 ;
    p1 = p2 ;
    p2 = p3 ;
    p3 = p3->next ;
    }
    p2->next = p1 ;
    head = p2 ;
    return head ;
    }
    

    (2)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序。(保留所有结点,即便大小相同)

    Node * Merge(Node *head1 , Node *head2)
    {
    if ( head1 == NULL)
    return head2 ;
    if ( head2 == NULL)
    return head1 ;
    Node *head = NULL ;
    Node *p1 = NULL;
    Node *p2 = NULL;
    if ( head1->data < head2->data )
    {
    head = head1 ;
    p1 = head1->next;
    p2 = head2 ;
    }
    else
    {
    head = head2 ;
    p2 = head2->next ;
    p1 = head1 ;
    }
    Node *pcurrent = head ;
    while ( p1 != NULL && p2 != NULL)
    {
    if ( p1->data <= p2->data )
    {
    pcurrent->next = p1 ;
    pcurrent = p1 ;
    p1 = p1->next ;
    }
    else
    {
    pcurrent->next = p2 ;
    pcurrent = p2 ;
    p2 = p2->next ;
    }
    }
    if ( p1 != NULL )
    pcurrent->next = p1 ;
    if ( p2 != NULL )
    pcurrent->next = p2 ;
    return head ;
    }
    

    (3)已知两个链表head1 和head2 各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。(Autodesk)
    答案:

    Node * MergeRecursive(Node *head1 , Node *head2)
    {
    if ( head1 == NULL )
    return head2 ;
    if ( head2 == NULL)
    return head1 ;
    Node *head = NULL ;
    if ( head1->data < head2->data )
    {
    head = head1 ;
    head->next = MergeRecursive(head1->next,head2);
    }
    else
    {
    head = head2 ;
    head->next = MergeRecursive(head1,head2->next);
    }
    return head ;
    }
    

    10.分析程序,得出结果

    class B
    {
    public:
    B()
    {
    cout<<"default constructor"<<endl;
    }
    ~B()
    {
    cout<<"destructed"<<endl;
    }
    B(int i):data(i) //B(int) works as a converter ( int ->instance of B)
    {
    cout<<"constructed by parameter "<< data <<endl;
    }
    private:
    int data;
    };
    
    B Play( B b) 
    {
    return b ;
    }
    (1) results:
    int main(int argc, char* argv[]) constructedby parameter 5
    { destructed B(5)形参析构
    B t1 = Play(5); B t2 = Play(t1);   destructed t1形参析构
    return0;               destructed t2 注意顺序!
    } destructed t1
    (2) results:
    int main(int argc, char* argv[]) constructedby parameter 5
    { destructed B(5)形参析构
    B t1 = Play(5); B t2 = Play(10);   constructed by parameter 10
    return0;               destructed B(10)形参析构
    } destructed t2 注意顺序!
    destructed t1
    

    11.判断一个单链表是否有环

    struct node { char val; node* next;}
    bool check(const node* head) {} //return false : 无环;true: 有环一种O(n)的办法就是(搞两个指针,一个每次递增一步,一个每次递增两步,如果有环的话两者必然重合,反之亦然):
    bool check(const node* head)
    {
    if(head==NULL) returnfalse;
    node *low=head, *fast=head->next;
    while(fast!=NULL && fast->next!=NULL)
    {
    low=low->next;
    fast=fast->next->next;
    if(low==fast) returntrue;
    }
    returnfalse;
    }
    

    12.编写类String的构造函数、析构函数和赋值函数,已知类String的原型为:

    class String
    { 
     public: 
      String(constchar*str = NULL); // 普通构造函数 
      String(const String &other); // 拷贝构造函数 
      ~ String(void); // 析构函数 
      String & operator =(const String &other); // 赋值函数 
     private: 
      char*m_data; // 用于保存字符串 
    };
      解答:
    //普通构造函数
    String::String(constchar*str) 
    {
     if(str==NULL) 
     {
      m_data =newchar[1]; // 得分点:对空字符串自动申请存放结束标志'\0'的空
      //加分点:对m_data加NULL 判断
      *m_data ='\0'; 
     } 
     else
     {
      int length = strlen(str); 
      m_data =newchar[length+1]; // 若能加 NULL 判断则更好 
      strcpy(m_data, str); 
     }
    }
    // String的析构函数
    String::~String(void) 
    {
     delete [] m_data; // 或deletem_data;
    }
    //拷贝构造函数
    String::String(const String &other)    // 得分点:输入参数为const型
    { 
     int length = strlen(other.m_data); 
     m_data =newchar[length+1];     //加分点:对m_data加NULL 判断
     strcpy(m_data, other.m_data); 
    }
    //赋值函数
    String & String::operator =(const String &other) // 得分点:输入参数为const型
    { 
     if(this==&other)   //得分点:检查自赋值
      return*this; 
     delete [] m_data;     //得分点:释放原有的内存资源
     int length = strlen( other.m_data ); 
     m_data =newchar[length+1];  //加分点:对m_data加NULL 判断
     strcpy( m_data, other.m_data ); 
     return*this;         //得分点:返回本对象的引用
    }
    

    相关文章

      网友评论

          本文标题:2017C++面试题

          本文链接:https://www.haomeiwen.com/subject/jkglattx.html