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();
可以編譯通過,只不過段錯誤。)

 

10、

 

 

11、

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 微軟亞洲技術中心的面試題!!!
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來看相當於結束符。)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 








免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM