問答題
問答題1:下列代碼輸出啥?
#include <iostream>
using namespace std;
void func(char **m) {
++m;
cout << *m << endl;
}
int main() {
static char *a[] = { "morning", "afternoon", "evening" };
char **p;
p = a;
func(p);
return 0;
}
提示:傳入到函數 func 中的是一個二級指針,進行++操作指向了 a[1] 這個位址,解引用得到 a[1] 值
這道題在C(弱類型)編譯環境可以通過,但是C++(強類型)編譯器不通過,因為 main 函數第一行左邊類型是const char* ,但是右邊是可變的指針數組,類型不比對
修改為
const char* a[] = { "morning", "afternoon", "evening" };
char **p;
p = (char**)a;
必須先讓等式兩邊類型相同,是以最後加個強制類型轉化;
答案:afternoon
問答題2:有如下程式?
class MyClass {
public:
MyClass(int i = 0) {
cout << 1;
}
MyClass(const MyClass&x) {
cout << 2;
}
MyClass& operator=(const MyClass&x) {
cout << 3;
return*this;
}
~MyClass() {
cout << 4;
}
};
int main() {
MyClass obj1(1), obj2(2), obj3(obj1);
system("pause");
return 0;
}
提示:調用兩次構造函數,一次拷貝拷貝構造函數,三次析構函數.
答案:112 444
問答題3:代碼執行後,a和b的值分别為?
class Test {
public:
int a;
int b;
virtual void fun() {}
Test(int temp1 = 0, int temp2 = 0){
a = temp1;
b = temp2;
}
int getA(){
return a;
}
int getB(){
return b;
}
};
int main(){
Test obj(5, 10);
int* pInt = (int*)&obj;
*(pInt + 0) = 100;
*(pInt + 1) = 200;
cout << "a = " << obj.getA() << endl;
cout << "b = " << obj.getB() << endl;
system("pause");
return 0;
}
提示:對象 obj 中的a 和 b 分别為 5 和 10,但是由于沒有重載運算符,是以強制轉換為整型運算,不過這不是關鍵,關鍵是fun函數,由于指向虛函數表的指針占4個位元組(32), 其位址分布在整個類成員變量的位址的首部,接下來才是變量a的位址、b的位址,是以 +0 表示的位址是虛表指針,+1 是a的位址,也就是說 b 并沒有被重新指派.
答案:a = 200,b=10
問答題4:32位系統中,定義**a[3][4],則變量占用記憶體空間為?
指針在32位系統,占 4個位元組,指針數組中一共有 12 個指針,是以占48位元組.
問答題5:執行下面語句後的輸出為?
int I=1;
if(I<=0){
printf("****\n") ;
}
else{
printf("%%%%\n");
}
提示:%%% 表示 輸出兩個百分号
答案:%%
問答題6:類模闆的使用實際上是先将類模闆執行個體化為模闆類,再執行個體化成一個具體的類
問答題7:下列代碼輸出啥?
struct A {
void foo() {
printf("foo");
}
virtual void bar() {
printf("bar");
}
A() {
bar();
}
};
struct B :A {
void foo() {
printf("b_foo");
}
void bar() {
printf("b_bar");
}
};
int main() {
A *p = new B;
p->foo();// B 中的 foo不是虛函數,是以會調用基類foo
p->bar();// 實作了多态,B 中含有 bar 的虛函數,調用派生類中的函數.
return 0;
}
提示:
A *p=newB;
/A 類指針指向一個執行個體化對象B, B類繼承A類,先調用父類的無參構造函數,bar()輸出
bar
,B類沒有自己顯示定義的構造函數,
p->foo();
執行B類裡的foo()函數,因為foo不是虛函數,是以直接調用父類的foo函數,輸出
foo
,
p->bar();
執行B類的bar()函數, 該函數為虛函數,調用子類的實作,輸出
b_bar
問答題8:下面的程式輸出可能是什麼?
class Printer {
public:
Printer(std::string name) {
std::cout << name;
}
};
class Container {
public:
Container()
: b("b")
, a("a")
{}
Printer a;
Printer b;
};
int main() {
Container c;
return 0;
}
提示:初始化根據類成員定義的順序,與初始化清單中的書寫的順序沒有關系,是以先初始化a,然後才是b
答案:
"ab"
問答題9:代碼可以通過編譯嗎?如果不能應該如何修改?
template<class T>
class Foo {
T tVar;
public:
Foo(T t) : tVar(t) { }
};
template<class T>
class FooDerived : public Foo<T> {
// 加入構造函數
};
int main(){
FooDerived<int> d(5);
return 0;
}
提示:當基類構造函數需要外部傳遞參數才能進行初始化時,派生類必須顯式定義構造函數,為基類傳遞參數;基類如果不需要傳遞或者可以不傳遞參數,派生類可以不用顯式定義構造函數。
答案:添加後如下圖.
template<class T>
class FooDerived : public Foo<T> {
public:
FooDerived(T val)
:Foo<T>(val)
{}
};
程式設計題
程式設計題1:另類加法
請編寫一個函數,将兩個數字相加。不得使用
+
或其他算數運算符,給定兩個int A和B,請傳回
A+B
的值
測試樣例:1,2;傳回:3
提示:利用二進制模拟加法運算.
int addAB(int A, int B) {
int sum = 0, carry = 0;
while (B != 0) {
//對應位的和
sum = A ^ B;
//對應位和的進位,既然是進位,就要整體左移一位
carry = (A&B) << 1;
A = sum;
B = carry;
}
return sum;
}
簡化代碼
int addAB(int A, int B) {
while (A & B << 1) {
//對應位的和
//對應位和的進位,既然是進位,就要整體左移一位
A = A ^ B;
}
return A;
}
遞歸寫法
int addAB(int A, int B) {
if(B==0){
return A;
}
return addAB(A^B,(A&B)<<1);
}
程式設計題2:求路徑總數
請編寫一個函數計算
n x m
的棋盤格子,沿着各自邊緣線從左上角走到右下角,總共有多少種走法,要求不能走回頭路,即:隻能往右和往下走,不能往左和往上走
示例1:輸入:2 2;輸出:6
方法一:遞歸計算路線,隻要 m 或 n 有一個等于1,則路線是 1+m 或者 1+ n ,如果有一個 等于 0,則傳回0
int pathNum(int n, int m){
if (n > 1 && m > 1){
return pathNum(n - 1, m) + pathNum(n, m - 1);
}else if (((n >= 1) && (m == 1))
|| ((n == 1) && (m >= 1))){
return n + m;
}
else{
return 0;
}
}
方法二:動态規劃
提示:初始化一個二維數組,多增加一行和一列,第一行和第一列為1,其餘位置都是0
周遊到目前位置時,
dp[i][j]
表示到達 (i,j)位置的個數
轉義方程為
dp[i][j] = dp[i-1][j] + dp[i][j-1];
最後傳回
dp[n][m]
位置的數字即是最終答案.
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n,m;
while(cin>>n>>m){
vector<vector<int>>dp(n+1,vector<int>(m+1,0));
for(int i=0;i<n+1;++i){
for(int j=0;j<m+1;++j){
if(i==0 || j==0){
dp[i][j] = 1;
}else{
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
}
}
cout<<dp[n][m]<<endl;
}
return 0;
}