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; // 記錄第一個字符下標位置,就是起始的字符位置0j = 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來看相當于結束符。)
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的C/C++练习题(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sklearn-标准化标签LabelEn
- 下一篇: mooc-IDEA 调试代码--012