zoukankan      html  css  js  c++  java
  • C/C++练习题(一)

    1. volatile 关键字在 C++ 中的性能和 C 的一样?

    作用是一样的,但是其内部实现原理可能不同。

    2. scanf 格式化输入是怎么赋值的?

    由于scanf输入的数据个数是不定的,从键盘输入的数据会进入缓冲流,然后将输入的数据赋值给scanf的参数。

    3. 下面代码的作用?

    void func(const char* input, char* output, unsigned int outLen)
    {
        int buf[256] = {0};
        while( *input )
        {
            buf[*input++]++;
        }
        if( output && outLen )
        {
            int i = 0;
            for(i=0; i<256; i++)
            {
                if( buf[i] )
                {
                    *output++ = (char)i;
                }
            }
            *output = 0;
        }
    }
    // 输入input为“aaabbbccddddd”,得到output为abcd



    1、下面的程序输出什么?为什么?(某 CPU 公司面试题)
    int main(int argc, char* argv[])
    {
        unsigned char a = 0xA5;
        unsigned char b = ~a >> 4 + 1;
        printf("%d ", b);
        return 0;

    }

    (分析:第一个坑:运算符优先级,+的优先级大于>>;第二个坑:当小类型变量和整型做运算的时候,会转化为int类型。

    这个题,将得到的int型的结果再截断,最后答案:250)

    6. 写程序判断一个数是否是 2 的 N 次方! (某 CPU 公司面试题)

    (分析:

    2的1次方:0000 0001

    2的2次方:0000 0010

    2的3次方:0000 0100

    那么,如果一个数是2的N次方,那么这个数的二进制就只有一个1.

    假设X这个数是2的N次方,(X-1 & X)必然等于0!!!

    
    7. 有 2 个数组保存着 100 以内的自然数,编程求出两个数组的交集(两个数组中同时出现的自然数)。

    #include <iostream>
    using namespace std;
    
    int main()
    {
        int a[] = {1, 2, 3, 4, 5, 6};
        int b[] = {3, 5, 7, 9};
        int buf[100] = {0};
        
        for(int i=0; i<sizeof(a)/sizeof(*a); i++)
        {
            buf[a[i]]++;
        }
        for(int i=0; i<sizeof(b)/sizeof(*b); i++)
        {
            if( buf[b[i]] )
                cout << b[i] << endl;
        }
        
        return 0;
    }

    8. 面试时如何被问及期望的薪水,该如何回答?

    (打听公司底薪+500)

    9. 职场新人应该注意些什么问题?

    (如果有的师傅不屌你,那么你就需要主动问师傅有什么杂活可以帮你做的,给师傅节省了时间,打好了关系,他才会也才有时间教你。不要坐着耗下去,因为即便跳槽也一样。)


    1.有一个问题: C++定义一个空类,编译器都会做些什么??

    (例如:定义Test空类

    class Test
    {
    };

    1:如果类中没有数据成员,那么编译器会给这个类分配固定的大小,VS是1,不可能是0

    2:编译器会在类中放入构造函数、拷贝构造函数、赋值运算符、析构函数。

    Test() {};

    Test(const Test& obj) {};

    Test& operator= (const Test& obj) {};

    ~Test() {};

    2.二阶构造法【为解决半成品的构造对象】

    (使用场所:当在构造函数里面申请资源,并且这个资源可能申请失败的时候

    分析:相当于将申请资源的步骤分为两个阶段:

    1:第一阶段申请不会出错的资源(类对象资源)

    2:第二阶段申请可能出错的资源,并进行判断,出错返回NULL,否则返回完整对象

    这样就有效地避免了半成品对象的产生!!!微笑

    4.对于一个给定的字符串,我们需要在线性(也就是O(n))的时间里对它做一些变形。
    首先这个字符串中包含着一些空格,就像"Hello World"一样,然后我们要做的是把这个字符串中
    由空格隔开的单词反序,同时反转每个字符的大小写。

    比如"Hello World"变形后就变成了"wORLD hELLO"

    (分析:

    步骤1:先将大小写字母反转;

    步骤2:再将整个字符串反转;

    步骤3:最后以空格为分界,每段的字符串再反转一次。

    代码如下:

    #include <iostream>
    using namespace std;
    
    // 字符大小写反转
    char change_char(char ch)
    {
    	char ret = ch;
    
    	if (('a' < ch) && (ch < 'z'))
    	{
    		ret = 'A' + ch - 'a';
    	}
    	else if (('A' < ch) && (ch < 'Z'))
    	{
    		ret = 'a' + ch - 'A';
    	}
    
    	return ret;
    }
    
    // 字符串反转
    void reverse(char s[], int index, int len)
    {
    	int i = index;  // 第一个位置下标
    	int j = index + len - 1;  // 最后一个位置下标
    
    	while ( i < j )
    	{
    		char t = s[i];
    		s[i] = s[j];
    		s[j] = t;
    
    		i++; j--;
    	}
    }
    
    void solution(char s[])
    {
    	int len = strlen(s);
    	int i = 0;
    
    	// 空间换时间
    	int* space = (int*)malloc(len * sizeof(int)); // 用来记录空格的位置
    	int* index = (int*)malloc(len * sizeof(int)); // 用来记录空格之后第一个字符的位置
    	int j = 0;
    	int k = 0;
    
    	for (i = 0; i<len; i++)
    	{
    		s[i] = change_char(s[i]);
    	}
    
    	cout << "1th: " << s << endl;
    
    	reverse(s, 0, len);
    
    	cout << "2th: " << s << endl;
    
    	for (i = 0; i<len; i++)
    	{
    		if (s[i] == ' ')
    		{
    			space[j] = i; // 记录第一个空格下标位置
    			index[j] = k; // 记录第一个字符下标位置,就是起始的字符位置0
    
    			j = j + 1;
    			k = i + 1;
    		}
    	}
    	// 最后字符串的结束符当做空格处理,所以需要再写一次
    	space[j] = i;
    	index[j] = k;
    
    	for (i = 0; i <= j; i++)
    	{
    		reverse(s, index[i], space[i] - index[i]);
    	}
    
    	free(space);
    	free(index);
    }
    
    
    
    int main()
    {
    	char str[] = "Hello World!";
    
    	cout << "before: " << str << endl;
    
    	solution(str);
    
    	cout << "after: " << str << endl;
    
    	return 0;
    }

     


    1、GetMemory函数用于申请一片内存空间,要使用二重指针。

    void GetMemory2(char **p, int num) 
    { 
          *p = (char *)malloc(sizeof(char) * num); 
    } 
    void main(void)
    { 
         char *str=NULL; 
         GetMemory=(&str); 
         strcpy(str,"hello world"); 
         printf(str); 
    }
    



    2、列举几种进程的同步机制,并比较其优缺点。

    答案:   原子操作  信号量机制     自旋锁    管程,会合,分布式系统  
     
    3、进程之间通信的途径 
    答案:共享存储系统消息传递系统管道:以文件系统为基础  
     
    4、进程死锁的原因 
    答案:资源竞争及进程推进顺序非法  
     
    5、死锁的 4个必要条件 
    答案:互斥、请求保持、不可剥夺、环路  
     
    6、死锁的处理 
    答案:鸵鸟策略、预防策略、避免策略、检测与解除死锁  
     
    7、操作系统中进程调度策略有哪几种? 
    答案:FCFS(先来先服务),优先级,时间片轮转,多级反馈  

    8、(void *)ptr  和 (*(void**))ptr 的结果是否相同?(其中 ptr为同一个指针) 

    答案:(void *)ptr  和 (*(void**))ptr值是相同的  

    9、要对绝对地址 0x100000 赋值,我们可以用  (unsigned int*)0x100000 = 1234;  那么要是
    想让程序跳转到绝对地址是 0x100000 去执行,应该怎么做? 
    答案:*((void (*)( ))0x100000 ) ( );  

    首先要将 0x100000 强制转换成函数指针,即: (void (*)())0x100000  

    然后再调用它: *((void (*)())0x100000)();  

    用 typedef 可以看得更直观些: 
    typedef void(*)() voidFuncPtr; 

    *((voidFuncPtr)0x100000)();  


    (但是在gcc里面编译会出错,但是写成:
    typedef void(*FuncType)();
    FuncType pf = (FuncType)0x10000;
    pf();
    可以编译通过,只不过段错误。)

    10、

    11、

     


     微软亚洲技术中心的面试题!!!
    1.进程和线程的差别。
    线程是指进程内的一个执行单元,也是进程内的可调度实体.
    与进程的区别:
    (1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
    (2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行
    (3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.
    (4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。

    2.测试方法

    人工测试:个人复查、抽查和会审

    机器测试:黑盒测试和白盒测试

    unsigned short A = 10;
    printf("~A = %u ", ~A);


    char c=128;
    printf("c=%d ",c);
    输出多少?并分析过程


    第一题,~A =0xfffffff5,int值 为-11,但输出的是uint。所以输出4294967285
    第二题,c=0x80,以char的8位字节来看,最高位为1,是负数。所以在内存的存储方式为补码(补码 = 反码 + 1)所以~(10000000-1)=-128
    这两道题都是在考察二进制向int或uint转换时的最高位处理。

    #include<iostream.h>
    #include <string.h>
    #include <malloc.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <memory.h>
    typedef struct AA
    {
            int b1:5;
            int b2:2;
    }AA;
    void main()
    {
            AA aa;
            char cc[100];
             strcpy(cc,"0123456789abcdefghijklmnopqrstuvwxyz");
           memcpy(&aa,cc,sizeof(AA));
            cout << aa.b1 <<endl;
            cout << aa.b2 <<endl;
    }
    答案是 -16和1
    首先sizeof(AA)的大小为4,b1和b2分别占5bit和2bit.
    经过strcpy和memcpy后,aa的4个字节所存放的值是:
    0,1,2,3的ASC码,即00110000,00110001,00110010,00110011
    所以,最后一步:显示的是这4个字节的前5位,和之后的2位
    分别为:10000,和01
    因为int是有正负之分  所以:答案是-16和1

    求函数返回值,输入x=9999;
    int func ( x )
    {
        int countx = 0;
        while ( x )
        {
            countx ++;
            x = x&(x-1);
        }
        return countx;
    }
    结果呢?
    知道了这是统计9999的二进制数值中有多少个1的函数,且有
    9999=9×1024+512+256+15
    9×1024中含有1的个数为2;
    512中含有1的个数为1;
    256中含有1的个数为1;
    15中含有1的个数为4;
    故共有1的个数为8,结果为8。
    1000 - 1 = 0111,正好是原数取反。这就是原理。
    用这种方法来求1的个数是很效率很高的。
    不必去一个一个地移位。循环次数最少。

    struct bit
    {   int a:3;
        int b:2;
        int c:3;
    };
    int main()
    {
    bit s;
    char *c=(char*)&s;
       cout<<sizeof(bit)<<endl;
    *c=0x99;
       cout << s.a <<endl <<s.b<<endl<<s.c<<endl;
         int a=-1;
       printf("%x",a);
    return 0;
    }
    输出为什么是
    4
    1
    -1
    -4
    ffffffff
    因为0x99在内存中表示为 100 11 001 , a = 001, b = 11, c = 100
    当c为有符合数时, c = 100, 最高1为表示c为负数,负数在计算机用补码表示,所以c = -4;同理
    b = -1;




    位域 :  
    有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:    
    struct 位域结构名    
    { 位域列表 };   
    其中位域列表的形式为: 类型说明符 位域名:位域长度    
    例如:    
    struct bs   
    {   
    int a:8;   
    int b:2;   
    int c:6;   
    };   
    位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:    
    struct bs   
    {   
    int a:8;   
    int b:2;   
    int c:6;   
    }data;   
    说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:   
    1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:    
    struct bs   
    {   
    unsigned a:4   
    unsigned :0 /*空域*/   
    unsigned b:4 /*从下一单元开始存放*/   
    unsigned c:4   
    }   
    在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。
    2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。   
    3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:    
    struct k   
    {   
    int a:1   
    int :2 /*该2位不能使用*/   
    int b:3   
    int c:2   
    };   
    从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。   

    (2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
    答:为了实现链式表达式。 // 2分
    例如 int length = strlen( strcpy( strDest, “hello world”) );

    编写类String的构造函数、析构函数和赋值函数
    已知类String的原型为:
    class String
    {
     public:
    String(const char *str = NULL);// 普通构造函数
    String(const String &other);   // 拷贝构造函数
    ~ String(void);   // 析构函数
    String & operate =(const String &other);// 赋值函数
     private:
    char   *m_data; // 用于保存字符串
    };
    请编写String的上述4个函数。


    标准答案:
    // String的析构函数
    String::~String(void)               // 3分
    {
    delete [] m_data;                    
    // 由于m_data是内部数据类型,也可以写成 delete m_data;
    }
    // String的普通构造函数             
    String::String(const char *str)      // 6分
    {
    if(str==NULL)                          
    {
    m_data = new char[1];    // 若能加 NULL 判断则更好
    *m_data = ‘’;                      
    }                                       
    else
    {
    int length = strlen(str);           
    m_data = new char[length+1];  // 若能加 NULL 判断则更好      
    strcpy(m_data, str);                
    }
    }
    // 拷贝构造函数
    String::String(const String &other)   // 3分
    {
    int length = strlen(other.m_data);
    m_data = new char[length+1];      // 若能加 NULL 判断则更好    
    strcpy(m_data, other.m_data);         
    }
    // 赋值函数
    String & String::operate =(const String &other)    // 13分
    {
    // (1) 检查自赋值                     // 4分
    if(this == &other)
    return *this;

    // (2) 释放原有的内存资源            // 3分
    delete [] m_data;

    // (3)分配新的内存资源,并复制内容 // 3分
    int length = strlen(other.m_data);
    m_data = new char[length+1];         // 若能加 NULL 判断则更好
    strcpy(m_data, other.m_data);

    // (4)返回本对象的引用            // 3分
    return *this;
    }


    请问下面程序有没有错误为什么?

    (段错误: char *strcpy(char *dest, const char *src);是拷贝字符串的函数,s只是字符数组,在结尾没有’’字符。)

    (strlen(a) = 255;因为char类型的范围为-256~255,当i=256时,a[256] = 1 0000 0000b, 产生截断,a[256]= 0,对于strlen来看相当于结束符。)








  • 相关阅读:
    Balanced Binary Tree
    Convert Sorted List to Binary Search Tree
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Validate Binary Search Tree
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Maximum Depth of Binary Tree
    如何把U盘的两个盘或者多个盘合成一个
    bugku 想蹭网先解开密码
  • 原文地址:https://www.cnblogs.com/lvonve/p/8832453.html
Copyright © 2011-2022 走看看