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\n", 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(); 可以编译通过,只不过段错误。)

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

2.测试方法

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

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

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

char c=128; printf("c=%d\n",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 = ‘\0’;                       }                                        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只是字符数组,在结尾没有’\0’字符。)

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏一枝花算不算浪漫

Thinking in java中关于Exception的一道面试题.

379160
来自专栏python3

python异常处理--try...except

在python中,用try来测试可能出现异常的语句,然后用except来处理可能出现的异常,try except的表达形式如下:

14620
来自专栏Spring相关

thymeleaf的常见问题汇总

31230
来自专栏算法修养

Code Forces 18D Seller Bob(简单DP)

D. Seller Bob time limit per test 2 seconds memory limit per test 128 mega...

32640
来自专栏面朝大海春暖花开

springMVC接受对象集合,name数组

这两天开发遇到一个很常见的问题,即使自己一直没遇见过,不过之前看过是实现接受对象集合的代码,只不过没注意罢了

17120
来自专栏云霄雨霁

Java--多态性之内部类和匿名类

18560
来自专栏java 成神之路

java 中的内省 introspector

28560
来自专栏机器学习算法与Python学习

Python:爬虫系列笔记(6) -- 正则化表达(推荐)

在前面我们已经搞定了怎样获取页面的内容,不过还差一步,这么多杂乱的代码夹杂文字我们怎样把它提取出来整理呢?下面就开始介绍一个十分强大的工具,正则表达式! 1.了...

37180
来自专栏深入浅出区块链技术

智能合约语言 Solidity 教程系列5 - 数组介绍

Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊、智能合约有所了解, 如果你还不了解,建议你先看以太坊是什么

12930
来自专栏Hongten

java 反射(Reflection)-干货

看了很多关于java 反射的文章,自己把所看到的总结一下。对自己,对他人或多或少有帮助吧。

11530

扫码关注云+社区

领取腾讯云代金券